Введение
Для технического обзора - перейдите к этому ответу .
Для распространенных случаев, когда происходит удаление копии - перейдите к этому ответу .
Копирование elision - это оптимизация, реализованная большинством компиляторов для предотвращения лишних (потенциально дорогих) копий в определенных ситуациях. Это делает возврат по значению или передачу по значению осуществимым на практике (применяются ограничения).
Это единственная форма оптимизации, которая исключает (ха!) Правило «как будто» - исключение копирования может применяться, даже если копирование / перемещение объекта имеет побочные эффекты .
Следующий пример взят из Википедии :
struct C {
C() {}
C(const C&) { std::cout << "A copy was made.\n"; }
};
C f() {
return C();
}
int main() {
std::cout << "Hello World!\n";
C obj = f();
}
В зависимости от компилятора и настроек допустимы следующие выходные данные :
Привет мир!
Копия была сделана.
Копия была сделана.
Привет мир!
Копия была сделана.
Привет мир!
Это также означает, что можно создавать меньше объектов, поэтому вы также не можете полагаться на определенное количество вызываемых деструкторов. У вас не должно быть критической логики внутри конструкторов копирования / перемещения или деструкторов, так как вы не можете полагаться на их вызов.
Если вызов конструктора копирования или перемещения исключен, этот конструктор должен все еще существовать и быть доступным. Это гарантирует, что исключение копирования не позволяет копировать объекты, которые обычно не копируются, например, потому что они имеют закрытый или удаленный конструктор копирования / перемещения.
C ++ 17 : Начиная с C ++ 17, Copy Elision гарантируется, когда объект возвращается напрямую:
struct C {
C() {}
C(const C&) { std::cout << "A copy was made.\n"; }
};
C f() {
return C(); //Definitely performs copy elision
}
C g() {
C c;
return c; //Maybe performs copy elision
}
int main() {
std::cout << "Hello World!\n";
C obj = f(); //Copy constructor isn't called
}