2009-10-13 8 views
6

¿Puede alguno de ustedes explicar por qué no se compila el siguiente fragmento de código?Error al tener un copiador privado con el operador de asignación pública

#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(); 
} 

El error que recibe:

$ 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: cuando quito la privada: palabra clave del código se compila pero el ctor copia nunca es llamado. Entonces, ¿por qué se equivoca cuando es privado?

No estoy seguro de si es importante, pero estoy usando:

$ g++ --version 
g++ (GCC) 4.1.2 20080704 (Red Hat 4.1.2-44) 
Copyright (C) 2006 Free Software Foundation, Inc. 
+1

FWIW: El código hace co mpile si asigna un objeto Foo creado previamente en lugar de un objeto temporal. Es decir. 'foo = bar;' en lugar de 'foo = Foo();'. – sepp2k

Respuesta

5

va a inicializar una referencia de temporal.
El estándar indica:
El temporal debe inicializarse (8.5.3 par 5) "utilizando las reglas para una inicialización de copia sin referencia (8.5)".

La construcción de la copia se elimina temporalmente (permitido por la norma 12.8 par 5).
Sin embargo, la norma establece claramente (12.2 par 1):
"Incluso cuando se evita la creación del objeto temporal (12.8), todas las restricciones semánticas deben respetarse como si se creara el objeto temporal. [Ejemplo: incluso si el constructor de copia no se llama, todas las restricciones semánticas, tales como la accesibilidad (cláusula 11), serán saciados.]"

(también, cuando se busca la cita derecha, encontraron esta duplicate :)

Editar: añadiendo ubicación relevante de la norma

+0

Esta respuesta es correcta, pero cita la parte incorrecta de '8.5.3 para 5' (en nuestro caso, tenemos tipos de clases y tipos compatibles de referencia, por lo que deben tomarse las viñetas * anteriores *). El más importante es el anterior y dice si copiar o no se define la implementación y luego "El constructor que se usaría para hacer la copia será invocable independientemente de que la copia se haya realizado o no". Para C++ 0x, la implementación ya no permite copiar y ya no necesitará un constructor de copia. –

+0

Me corresponde corregir :) gracias –

+0

Gracias, aprendí algo nuevo hoy. – sdumi

1

Copia Ctor se llama cuando:

  1. pasar un objeto de valor como parámetro a una función,
  2. devolver una objeto de una función.

Así que ciertamente estás haciendo una o ambas de estas cajas en algún lugar de tu código. Debes configurar Copy Ctor como público o evitar los 2 casos anteriores.

+0

Lo hizo. Intenta compilar su código. El error se plantea (sin ningún código adicional) –

0

constructor de copia se llamaría si se escribe

Foo foo; // normal constructor 
Foo foo1(foo); //copy constructor 

En su caso, en primer lugar el constructor por defecto se llama y luego el operador = método.

+0

Entonces, ¿por qué su código no se compila? – sepp2k

+0

¿Quizás su código no compila con Werror? ;) – UncleBens

3

Suponiendo que el código que has enviado es el único código en el proyecto, y no hay paso encubierta de Foos por valor de ir en cualquier lugar, todo lo que puedo imaginar es que gcc es la optimización de

Foo foo; 
foo = Foo(); 

a

Foo foo = Foo(); 

... que es poco sólido, como la primera forma es un default-constructo y una asignación, mientras que el segundo es equivalente a

Foo foo(Foo()); 

... que es claramente una construcción de copia. Si estoy en lo cierto, el constructor de copias no se está ejecutando porque GCC puede optimizar el temporal redundante; esto está permitido por la especificación de C++.

En general, no es una buena idea tener operadores de asignación y constructores de copia en diferentes niveles de protección; como has visto, los resultados pueden ser poco intuitivos.

+0

gcc no puede optimizar los constructores de ese tipo, ya que tienen efectos secundarios (el 'cout's). Si gcc hace eso, es un error. – CAdaker

+0

@CAdaker: no. La eliminación de temporales temporales es un caso especial y el estándar de C++ permite explícitamente eludir la construcción de copias en esas circunstancias. –

+0

Incluso cuando los temporales tienen constructores y destructores no triviales? Eso suena completamente loco. – CAdaker

4

Ese código se compila con gcc 4.3.3 y 4.4.1. Tal vez eso es solo un error en gcc 4.1?

+0

¿Puedes intentar recompilar en estas versiones usando -Wall? Gracias –

+0

Recibo advertencias sobre operator = no devolver un valor, pero de lo contrario nada. – CAdaker

+0

Me falla: usando g ++ (GCC) 3.4.4 –

-1
#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 
} 

comprobar esto, en Foo f2=f1; (f2 se crea usando constructor de copia)

+0

¿Qué intentas decir en el código anterior? Se preguntó por qué se está produciendo un error de compilación cuando el constructor de copia es privado. Acabas de dar un ejemplo de constructor predeterminado y constructor de copia. – Jagannath

Cuestiones relacionadas