Copy elision é uma técnica de otimização de compilador que elimina a cópia / movimentação desnecessária de objetos.
Nas seguintes circunstâncias, um compilador pode omitir operações de copiar / mover e, portanto, não chamar o construtor associado:
- NRVO (Otimização de Valor de Retorno Nomeado) : se uma função retornar um tipo de classe por valor e a expressão da instrução de retorno for o nome de um objeto não volátil com duração de armazenamento automática (que não é um parâmetro de função), copie / mova que seria executado por um compilador não otimizador pode ser omitido. Nesse caso, o valor retornado é construído diretamente no armazenamento para o qual o valor de retorno da função seria movido ou copiado.
- RVO (Return Value Optimization) : se a função retornar um objeto temporário sem nome que seria movido ou copiado no destino por um compilador ingênuo, a cópia ou movimentação poderá ser omitida conforme 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
Mesmo quando a elisão da cópia ocorre e o copiador / movedor-construtor não é chamado, ele deve estar presente e acessível (como se não houvesse otimização), caso contrário, o programa não está formado.
Você deve permitir a remoção dessa cópia apenas em locais onde não afetará o comportamento observável do seu software. A cópia elision é a única forma de otimização permitida a ter (ou seja, elide) efeitos colaterais observáveis. Exemplo:
#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
O GCC oferece a -fno-elide-constructors
opção de desativar a cópia elision. Se você deseja evitar possíveis elisiones de cópia, use -fno-elide-constructors
.
Agora, quase todos os compiladores fornecem cópia elision quando a otimização está ativada (e se nenhuma outra opção estiver configurada para desativá-la).
Conclusão
Com cada cópia eliminada, uma construção e uma destruição correspondente da cópia são omitidas, economizando tempo de CPU e um objeto não é criado, economizando espaço no quadro da pilha.