referência const para temporária e cópia - C++
-
24-09-2019 - |
Pergunta
Por favor, considere o seguinte código,
struct foo
{
foo()
{
std::cout << "Constructing!" << std::endl;
}
foo(const foo& f)
{
std::cout << "Copy constructing!" << std::endl;
}
~foo()
{
std::cout << "Destructing.." << std::endl;
}
};
foo get()
{
foo f;
return f;
}
int main()
{
const foo& f = get();
std::cout << "before return" << std::endl;
return 0;
}
Saída em MSVC
Constructing!
Copy constructing!
Destructing..
before return
Destructing..
Saída do GCC
Constructing!
before return
Destructing..
O resultado que vem no MSVC parece incorreto.
Questões
- AFAIK, GCC produz o resultado correto aqui.Por que o MSVC está dando resultados diferentes e por que está fazendo a construção de cópias?
const foo& f = get()
econst foo f = get()
produz a mesma saída devido à otimização do valor de retorno.Nesse caso, qual forma de escrita deve ser preferida?
Alguma ideia..
Solução
Sua compilação MSVC não tem otimizações. Ligue -os, você receberá uma saída idêntica para ambos.
O GCC está apenas executando, por padrão, RVO no seu temporário. Está basicamente fazendo:
const foo& f = foo();
MSVC não é. Está fazendo o foo
Na função, copiando-a para a função externa (ergo a chamada de cópia-construtor), destruindo o interior foo
, então liga a referência.
Ambas as saídas estão corretas. O RVO é uma instância em que o padrão permite explicitamente o comportamento observável do programa.
Outras dicas
Você está vendo o Otimização do valor de retorno, que é um tipo de Copie a elisão. Ambos os programas estão corretos; O compilador recebe especificamente a opção de eliminar um temporário que serve apenas para mover dados de um objeto permanente para outro.
A função get() está construindo o local (print Construindo!) E retornando um objeto Foo por valor.O objeto Foo que está sendo retornado deve ser criado e isso é feito por meio da construção de cópia (construção de cópia de impressão!).Observe que este é o valor do objeto atribuído a const foo & f em main.
Antes que essa atribuição ocorra, a função deve retornar de get() e de variáveis locais (ou seja,foo f;em get()) deve ser destruído.(print 1st Destructing..) A partir daí o programa termina (ou seja,retorna de main), então o objeto retornado por get() e atribuído a "f" é destruído.(imprimir 2ª Destruição...)
A razão pela qual você está vendo resultados diferentes para os dois compiladores é que o GCC está otimizando o valor de retorno de get() e simplesmente substituindo const foo &f = get()
para const foo &f = foo
;
1) Isso acontece devido a diferentes estratégias de otimização. Como você não possui operador =, o MSVC pode reestruturar o código em algo como const foo & f (get ()) executando, portanto, cópia onStructor. 2) Depende do que você deseja acertar:
const foo& f = get();
f = get(); // Incorrect, const references cannot be reassigned.
const foo g = get();
g = get(); // Correct.