2011-01-19 19 views
22

Estoy pasando un objeto temporal sin nombre a una función definida con el parámetro const ref. El copiador de la clase es privado y obtengo un error de compilación. No entiendo por qué se llama a un constructor de copia en esta situación.¿por qué se llama al constructor de copia cuando pasa temporalmente por referencia de referencia?

class A { 
public: 
    A(int i) {} 
private: 
    A(const A&) {} 
}; 

void f(const A& a) 
{ 
} 

int main() 
{ 
    f(A(1)); // <-- error here: 'A::A(const A&)' is private 
} 

Como era de esperar, cuando cambio la principal a:

A a(1); 
f(a); 

funciona.

EDIT: el compilador gcc 4.1.2 es

+0

¿Qué compilador estás usando? – sharptooth

+0

VC++ 9 se complace en compilar la primera variante. – sharptooth

+0

@sharptooth: gcc, actualizaré – davka

Respuesta

17

Puede encontrar la respuesta a su pregunta en Copy Constructor Needed with temp object o ir directamente a http://gcc.gnu.org/bugs/#cxx%5Frvalbind

El estándar de C++ dice que un objeto temporal se debe crear en este contexto y su contenido lleno de una copia de el objeto que intentamos se une a la referencia; también dice que la copia temporal puede elide, pero las restricciones semánticas (por ejemplo, accesibilidad ) del constructor de copia aún tienen que ser verificadas.

Para más información, puede consultar los siguientes párrafos de el estándar C++: [dcl.init.ref]/5, bala 2, sub-bala 1, y [class.temporary]/2.

Comenzando con GCC 4.3.0, GCC ya no da un error en este caso.Este cambio se basa en la intención del comité de lenguaje C++ . A partir del 2010-05-28, el borrador final propuesto del estándar C++ 0x permite este código sin error.

+2

+1 para una buena información! – Nawaz

0

Debido a un (1) llama al constructor A (int i) y A (const Un &) se llama en la llamada a anular f (const Un &)

Haga que el constructor A (int i) sea explícito y no debe enfrentar este error.

Editar: Creo que he entendido mal la pregunta. Podría borrar esto.

+0

** Del estándar C++ §3.2 párrafo 2 : ** Se utiliza un constructor de copia incluso si la llamada a la es eliminada por la implementación . – dalle

+2

El constructor de copia no debe llamarse conceptualmente aquí, ese es el punto de la pregunta. Pasar por referencia implica que no hay creación de un nuevo objeto, por lo tanto no hay copia. – sharptooth

+0

¿Por qué votar abajo? En realidad es correcto, de acuerdo con el estándar. – dalle

18

La expresión A(1) es rvalue 5.2.3 [expr.type.conv].

En la inicialización de una referencia const (el argumento de la función) con una expresión que es una rvalue el compilador puede crear una copia temporal y el valor de esa expresión a la temporal y obligar a que la referencia que temporal. 8.5.3 [dcl.init.ref]/5.

[...] El constructor que se usaría para hacer la copia se podrá llamar independientemente de que la copia se haya realizado o no.

Tenga en cuenta que este comportamiento se debe a un cambio en la próxima versión de C++. En el nuevo estándar, una referencia const inicializada desde una clase prvalue debe vincularse directamente al objeto de referencia; no se permite que se cree temporal en este caso y no se usa ni se requiere un constructor de copia.

+0

¡+1 por ser correcto! – Nawaz

+0

gracias. su último párrafo explica por qué esto no sucede en la versión más nueva de gcc según el comentario de @Nawaz, ¿correcto? – davka

+0

@davka: Creo que esa es la razón, sí. –

Cuestiones relacionadas