Performance Guidelines
Writing efficient modern C++ without sacrificing readability
Memory Management
// BAD: Frequent allocations
for (int i = 0; i < n; ++i) {
auto obj = std::make_unique<ExpensiveObject>(); // n allocations!
// use obj...
}
// GOOD: Reuse memory
auto obj = std::make_unique<ExpensiveObject>();
for (int i = 0; i < n; ++i) {
obj->reset(); // Reuse allocated memory
// use obj...
}
// BAD: Resizing vector in loop
std::vector<int> v;
for (int i = 0; i < 1000; ++i) {
v.push_back(i); // Multiple reallocations
}
// GOOD: Reserve capacity
std::vector<int> v;
v.reserve(1000); // Single allocation
for (int i = 0; i < 1000; ++i) {
v.push_back(i);
}Move vs Copy
// BAD: Unnecessary copy
std::vector<BigObject> process(const std::vector<BigObject>& input) {
std::vector<BigObject> result = input; // Copy!
// modify result...
return result;
}
// GOOD: Pass by value + move
std::vector<BigObject> process(std::vector<BigObject> input) {
// modify input in place...
return input; // NRVO or move
}
// Usage
auto result = process(std::move(data)); // Move, no copy
// BAD: Not moving when appropriate
auto ptr = std::make_unique<Resource>();
consume(ptr); // Copy (if passed by value) or doesn't compile
// GOOD: Explicit move
consume(std::move(ptr)); // Transfer ownershipAlgorithm Selection
// BAD: O(n^2) lookup in loop
for (const auto& item : items) {
if (std::find(large_vector.begin(), large_vector.end(), item) != large_vector.end()) {
// Found!
}
}
// GOOD: Use unordered_set for O(1) lookup
std::unordered_set<Item> item_set(large_vector.begin(), large_vector.end());
for (const auto& item : items) {
if (item_set.contains(item)) {
// Found! O(1)
}
}
// BAD: Sorting already sorted data
std::sort(data.begin(), data.end()); // O(n log n)
// GOOD: Check if sorted first
if (!std::is_sorted(data.begin(), data.end())) {
std::sort(data.begin(), data.end());
}Cache Efficiency
// BAD: Column-major access (cache unfriendly)
for (size_t col = 0; col < cols; ++col) {
for (size_t row = 0; row < rows; ++row) {
matrix[row][col] += 1; // Jumps in memory
}
}
// GOOD: Row-major access (cache friendly)
for (size_t row = 0; row < rows; ++row) {
for (size_t col = 0; col < cols; ++col) {
matrix[row][col] += 1; // Sequential access
}
}
// BAD: Vector of pointers (scattered memory)
std::vector<std::unique_ptr<Object>> objects;
// GOOD: Contiguous storage
std::vector<Object> objects;
// If polymorphism needed, consider:
std::vector<std::variant<Type1, Type2, Type3>> objects;