| name | cpp |
| description | Language-specific super-code guidelines for cpp. |
| risk | safe |
| source | community |
| date_added | 2026-06-16 |
C++: Idiomatic Efficiency Reference
Table of Contents
- Memory & Ownership
- Modern Types & Containers
- Move Semantics & References
- Templates & Concepts
- Error Handling
- Concurrency
- Anti-patterns specific to C++
1. Memory & Ownership {#memory}
Widget* w = new Widget();
delete w;
auto w = std::make_unique<Widget>();
auto w = std::make_shared<Widget>();
transfer(w);
auto w = std::make_unique<Widget>();
transfer(std::move(w));
int* arr = new int[n];
delete[] arr;
std::vector<int> arr(n);
FILE* f = fopen(path, "r");
std::ifstream f(path);
auto f = std::unique_ptr<FILE, decltype(&fclose)>(fopen(path, "r"), fclose);
Rule: if you type new, you almost certainly want make_unique or make_shared.
2. Modern Types & Containers {#types}
char buf[256];
sprintf(buf, "%s:%d", host, port);
auto addr = std::format("{}:{}", host, port);
void compute(int input, int& result, std::string& error);
struct ComputeResult { int value; std::string error; };
ComputeResult compute(int input);
auto [value, error] = compute(input);
int idx = -1;
for (int i = 0; i < vec.size(); i++) {
if (vec[i] == target) { idx = i; break; }
}
auto it = std::ranges::find(vec, target);
auto it = map.find(key);
if (it != map.end()) { use(it->second); }
if (map.contains(key)) { use(map[key]); }
Use std::string_view for function parameters that don't need ownership.
3. Move Semantics & References {#move}
void process(std::vector<Data> items) { ... }
void process(const std::vector<Data>& items) { ... }
void consume(std::vector<Data> items) { ... }
const std::string s = "hello";
take(std::move(s));
std::string s = "hello";
take(std::move(s));
std::vector<int> build() {
std::vector<int> v;
return std::move(v);
return v;
}
4. Templates & Concepts {#templates}
template<typename T, typename = std::enable_if_t<std::is_integral_v<T>>>
T square(T x) { return x * x; }
template<std::integral T>
T square(T x) { return x * x; }
template<typename T>
void log(T msg) { std::cout << msg; }
void log(std::string_view msg) { std::cout << msg; }
Concepts make template errors readable — prefer them over SFINAE and static_assert.
5. Error Handling {#errors}
int parse(const std::string& input, Data& out);
std::expected<Data, ParseError> parse(const std::string& input);
Data parse(const std::string& input);
try { ... }
catch (std::exception e) { ... }
catch (const std::exception& e) { ... }
~MyClass() {
if (cleanup() < 0) throw CleanupError();
~MyClass() noexcept {
if (cleanup() < 0) log_error("cleanup failed");
}
6. Concurrency {#concurrency}
std::thread t(work);
std::jthread t(work);
mtx.lock();
data.push_back(item);
mtx.unlock();
{
std::scoped_lock lock(mtx);
data.push_back(item);
}
while (!done.load()) { std::this_thread::sleep_for(10ms); }
auto future = std::async(std::launch::async, compute);
auto result = future.get();
Use std::scoped_lock over lock_guard — it handles multiple mutexes and avoids deadlock.
7. Anti-patterns specific to C++ {#antipatterns}
| Anti-pattern | Preferred |
|---|
Raw new/delete | make_unique / make_shared |
(Type)expr C-style cast | static_cast<Type>(expr) |
#define constants | constexpr variables |
NULL | nullptr |
using namespace std; in headers | explicit std:: prefix |
| Manual loop for transform/filter | std::ranges or <algorithm> |
std::endl | '\n' (endl flushes — slow) |
char* for string parameters | std::string_view |
Exception specification throw() | noexcept |
Inheriting from std:: containers | composition, not inheritance |
volatile for thread synchronization | std::atomic |
| Header-only mega-templates | separate declaration/definition where compile time matters |
Limitations
- These are language-specific guidelines and do not cover overall architectural decisions.
- Over-compression might reduce readability; apply judgement.