estranho C ++ construtor / copiar questões construtor em g ++
-
05-07-2019 - |
Pergunta
#include <iostream>
using namespace std;
class X {
public:
X() {
cout<<"Cons"<<endl;
}
X(const X& x){
cout<<"Copy"<<endl;
}
void operator=(const X& x){
cout<<"Assignment called";
}
};
X& fun() {
X s;
return s;
}
int main(){
X s = fun();
return 0;
}
Este código chama o construtor de cópia também. Por que isso funciona? Lembro-me que a primeira vez que eu corri este programa, o seg criticada. Mas depois de um tempo, ele começou a chamar esta cópia contras. e agora trabalha !! Estranho.
Mas se eu substituir, fun () da seguinte forma:
X fun() {
X s;
return s;
}
Em seguida, copie os contras. não é chamado. Eu pensei que os contras de cópia. seria chamado neste caso. Mas, como fora apontado por @ flyfishr64, RVO está entrando em jogo aqui. Mas ainda não explica o caso em que estou retornando uma referência. Eu acho que deve sempre segfault.
Qualquer explicações?
Solução
Para expandir a resposta de @ flyfishr64
O construtor de cópia é invocado aqui porque esta:
X s = fun();
é uma inicialização. Você está usando fun () para construir o objeto, não invocando o construtor padrão. É equivalente a:
X s(fun());
Os "Contras" que você vê impresso é para a instância em fun (). Veja este artigo:. Operador de atribuição em C ++ para mais
Outras dicas
Esta referência retorna a um objeto na pilha que não existe uma vez que o método retorna - a pilha está desenrolados, a memória ainda está lá, mas você não deve usá-lo
X& fun() {
X s;
return s;
}
Quando você mudar isso para:
X fun() {
X s;
return s;
}
Você agora estão voltando uma cópia. Se o compilador é suficiente inteligente que pode fazer:
X fun() {
return X();
}
Nesse caso, o X
é alocado diretamente nas chamadas empilhar de modo que a cópia não é necessária.
Se segfault ou não depende se você está acessando a memória inválida.
No seu exemplo você não acessar quaisquer valores a partir da estrutura. Para ver segfault, primeiro manter uma referência que você voltou com fun()
adicionar algumas variáveis ??na estrutura X
e depois do retorno de fun()
chamar outro método que atribui internamente alguma memória na pilha (isso deve substituir a memória original usado por X
em fun
) e lojas de alguns valores na pilha (de preferência 0) da. Após este segundo método retorna tentar imprimir valores do X
utilizando a referência original retornou de fun
...
Neste código:
X fun() {
X s;
return s;
}
o construtor de cópia não está sendo chamado por causa do valor de retorno de otimização que permite que o compilador para ignorar a criação da variável local 's' e construir X diretamente na variável devolvidos.
Você pode ler mais sobre RVO aqui
Quando você retornar uma referência a uma variável local como esse, você está invocando o comportamento undefinied.
Acontece a trabalho neste caso, porque nenhuma das funções de class X
realmente usar o ponteiro this
, por isso não importa que ele não é mais válido.