Erro quando tem cópia privada ctor com operador de atribuição pública
-
21-09-2019 - |
Pergunta
Um de vocês pode explicar por que a seguinte parte do código não é compilada?
#include <iostream>
using namespace std;
class Foo
{
public:
Foo() { cout << "Foo::Foo()" << endl << endl; }
Foo& operator=(const Foo&) { cout << "Foo::operator=(const Foo&)" << endl << endl; }
private:
Foo(const Foo& b) { *this = b; cout << "Foo::Foo(const Foo&)" << endl << endl; }
};
int main()
{
Foo foo;
foo = Foo();
}
O erro que recebo:
$ g++ -o copy_ctor_assign copy_ctor_assign.cc && ./copy_ctor_assign
copy_ctor_assign.cc: In function 'int main()':
copy_ctor_assign.cc:10: error: 'Foo::Foo(const Foo&)' is private
copy_ctor_assign.cc:17: error: within this context
Nota: Quando eu removo o privado: Palavra -chave A compila de código, mas o ctor não é chamado. Então, por que errar quando é privado?
Não tenho certeza se é importante, mas estou usando:
$ g++ --version
g++ (GCC) 4.1.2 20080704 (Red Hat 4.1.2-44)
Copyright (C) 2006 Free Software Foundation, Inc.
Solução
Você está inicializando uma referência temporária.
Os estados padrão:
O temporário deve ser inicializado (8.5.3 par 5) "Usando as regras para uma inicialização de cópia de não referência (8.5)".
A construção da cópia é removida para o temporário (permitido pelo padrão. 12.8 par 5).
No entanto, o padrão afirma claramente (12.2 par 1):
"Mesmo quando a criação do objeto temporário é evitada (12,8), todas as restrições semânticas devem ser respeitadas como se o objeto temporário fosse criado. [Exemplo: mesmo que o construtor de cópias não fosse chamado, todas as restrições semânticas, como a acessibilidade (Cláusula 11), deve ser satisfeito.] "
(Além disso, ao procurar a citação certa, achei isso duplicado :)
Editar: Adicionando localização relevante do padrão
Outras dicas
Esse código compila com o GCC 4.3.3 e 4.4.1. Talvez seja apenas um bug no GCC 4.1?
Supondo que o código que você postou seja o único código no projeto, e não há passagem secreta do FOOS por valor em qualquer lugar, tudo o que posso imaginar é que o GCC está otimizando
Foo foo;
foo = Foo();
para
Foo foo = Foo();
... o que não é dono, pois o primeiro formulário é uma construção padrão e uma tarefa, enquanto o segundo é equivalente a
Foo foo(Foo());
... que é claramente uma construção de cópia. Se eu estiver certo, o construtor de cópias não está sendo executado porque o GCC pode otimizar o redundante temporário; Isso é permitido pela especificação C ++.
Em geral, não é uma boa idéia ter operadores de tarefas e copiar construtores em diferentes níveis de proteção; Como você viu, os resultados podem ser inintivos.
Cópia ctor é chamada quando:
- passando um objeto por valor como parâmetro para uma função,
- retornando um objeto de uma função.
Então, você certamente está fazendo um ou ambos os casos em algum lugar do seu código. Você deve definir cópia como público ou evitar os 2 casos anteriores.
Cópia do construtor seria chamado se você escrever
Foo foo; // normal constructor
Foo foo1(foo); //copy constructor
No seu caso, primeiro o construtor padrão é chamado e, em seguida, o Método Operador =.
#include <iostream>
using namespace std;
class Foo
{
public:
Foo() { cout << "Foo::Foo()" << endl << endl; }
Foo& operator=(const Foo&) { cout << "Foo::operator=(const Foo&)" << endl << endl; }
Foo(const Foo& b) { *this = b; cout << "Foo::Foo(const Foo&)" << endl << endl; }
};
int main()
{
Foo f1;// default constructor called
Foo f2 = f1; //copy constructor called
}
Verifique isso, em Foo f2=f1;
( f2
é criado usando o copy construtor)