Appearance
Copy-Move Elision
Copy-move elision is a compiler optimization that eliminates unnecessary copy and move operations, even when they would have observable side effects. This optimization is mandatory in C++17 and later, meaning the compiler must perform it when possible.
Return Value Optimization (RVO)
RVO eliminates the copy/move of a temporary object when returning from a function.
Named Return Value Optimization (NRVO)
NRVO is a specific form of RVO that applies when returning a named local variable.
cpp
// Without NRVO (conceptually):
Widget createWidget() {
Widget w; // Construct w
w.setValue(42);
return w; // Copy w to return value
}
// With NRVO (what actually happens):
Widget createWidget() {
Widget w; // Construct w directly in return location
w.setValue(42);
// No copy - w is already in the right place
}Unnamed Return Value Optimization
Applies when returning a temporary object:
cpp
Widget createWidget() {
return Widget(42); // No copy - constructed directly in return location
}Copy Elision in Different Contexts
1. Function Return Values
cpp
class ExpensiveObject {
std::vector<int> data;
public:
ExpensiveObject() : data(1000000) {}
ExpensiveObject(const ExpensiveObject& other) : data(other.data) {
std::cout << "Copy constructor called!" << std::endl;
}
ExpensiveObject(ExpensiveObject&& other) noexcept : data(std::move(other.data)) {
std::cout << "Move constructor called!" << std::endl;
}
};
ExpensiveObject createObject() {
ExpensiveObject obj; // NRVO applies here
return obj; // No copy/move - obj is constructed in return location
}
int main() {
ExpensiveObject result = createObject(); // No copy/move
return 0;
}2. Exception Handling
cpp
void throwObject() {
ExpensiveObject obj;
throw obj; // Copy elision applies to thrown objects
}3. Initialization with Temporary
cpp
ExpensiveObject obj = ExpensiveObject(); // Copy elision appliesWhen Copy Elision Cannot Be Applied
1. Multiple Return Paths
cpp
ExpensiveObject createObject(bool flag) {
if (flag) {
ExpensiveObject obj1;
return obj1; // NRVO applies
} else {
ExpensiveObject obj2;
return obj2; // NRVO applies
}
// But if we had:
// ExpensiveObject obj1, obj2;
// if (flag) return obj1;
// else return obj2;
// NRVO might not apply due to multiple return paths
}2. Return by Reference
cpp
ExpensiveObject& createObject() {
static ExpensiveObject obj; // Must return reference
return obj; // No elision possible
}3. Virtual Functions
cpp
class Base {
public:
virtual ExpensiveObject create() = 0;
};
class Derived : public Base {
public:
ExpensiveObject create() override {
ExpensiveObject obj;
return obj; // NRVO applies
}
};Performance Implications
- Latency Reduction: Eliminating unnecessary copies reduces CPU cycles
- Memory Bandwidth: Fewer memory operations mean lower latency
- Cache Efficiency: Less memory movement improves cache performance
- Predictable Performance: Consistent optimization across compilers