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?

Foi útil?

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.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top