Copy elision es una técnica de optimización del compilador que elimina la copia / movimiento innecesario de objetos.
En las siguientes circunstancias, un compilador puede omitir operaciones de copiar / mover y, por lo tanto, no llamar al constructor asociado:
- NRVO (Optimización de valor de retorno con nombre) : si una función devuelve un tipo de clase por valor y la expresión de la declaración de retorno es el nombre de un objeto no volátil con una duración de almacenamiento automática (que no es un parámetro de función), entonces la copia / mover eso sería realizado por un compilador no optimizador puede omitirse. Si es así, el valor devuelto se construye directamente en el almacenamiento al que, de lo contrario, el valor devuelto de la función se movería o copiaría.
- RVO (Optimización del valor de retorno) : si la función devuelve un objeto temporal sin nombre que sería movido o copiado en el destino por un compilador ingenuo, la copia o el movimiento se pueden omitir según 1.
#include <iostream>
using namespace std;
class ABC
{
public:
const char *a;
ABC()
{ cout<<"Constructor"<<endl; }
ABC(const char *ptr)
{ cout<<"Constructor"<<endl; }
ABC(ABC &obj)
{ cout<<"copy constructor"<<endl;}
ABC(ABC&& obj)
{ cout<<"Move constructor"<<endl; }
~ABC()
{ cout<<"Destructor"<<endl; }
};
ABC fun123()
{ ABC obj; return obj; }
ABC xyz123()
{ return ABC(); }
int main()
{
ABC abc;
ABC obj1(fun123());//NRVO
ABC obj2(xyz123());//NRVO
ABC xyz = "Stack Overflow";//RVO
return 0;
}
**Output without -fno-elide-constructors**
root@ajay-PC:/home/ajay/c++# ./a.out
Constructor
Constructor
Constructor
Constructor
Destructor
Destructor
Destructor
Destructor
**Output with -fno-elide-constructors**
root@ajay-PC:/home/ajay/c++# g++ -std=c++11 copy_elision.cpp -fno-elide-constructors
root@ajay-PC:/home/ajay/c++# ./a.out
Constructor
Constructor
Move constructor
Destructor
Move constructor
Destructor
Constructor
Move constructor
Destructor
Move constructor
Destructor
Constructor
Move constructor
Destructor
Destructor
Destructor
Destructor
Destructor
Incluso cuando se realiza una elisión de copia y no se llama al constructor de copia / movimiento, debe estar presente y accesible (como si no hubiera sucedido ninguna optimización), de lo contrario, el programa está mal formado.
Debe permitir dicha copia de elisión solo en lugares donde no afecte el comportamiento observable de su software. Copiar elisión es la única forma de optimización que permite tener (es decir, eludir) efectos secundarios observables. Ejemplo:
#include <iostream>
int n = 0;
class ABC
{ public:
ABC(int) {}
ABC(const ABC& a) { ++n; } // the copy constructor has a visible side effect
}; // it modifies an object with static storage duration
int main()
{
ABC c1(21); // direct-initialization, calls C::C(42)
ABC c2 = ABC(21); // copy-initialization, calls C::C( C(42) )
std::cout << n << std::endl; // prints 0 if the copy was elided, 1 otherwise
return 0;
}
Output without -fno-elide-constructors
root@ajay-PC:/home/ayadav# g++ -std=c++11 copy_elision.cpp
root@ajay-PC:/home/ayadav# ./a.out
0
Output with -fno-elide-constructors
root@ajay-PC:/home/ayadav# g++ -std=c++11 copy_elision.cpp -fno-elide-constructors
root@ajay-PC:/home/ayadav# ./a.out
1
GCC ofrece la -fno-elide-constructors
opción de deshabilitar la copia de elisión. Si desea evitar una posible elisión de copia, úsela -fno-elide-constructors
.
Ahora, casi todos los compiladores proporcionan copia de elisión cuando la optimización está habilitada (y si no hay otra opción configurada para deshabilitarla).
Conclusión
Con cada elisión de copia, se omite una construcción y una destrucción coincidente de la copia, lo que ahorra tiempo de CPU y no se crea un objeto, ahorrando así espacio en el marco de la pila.