17

Para este programaC++ constructor de copia, los temporales y la semántica copia

#include <iostream> 
using std::cout; 

struct C 
{ 
    C() { cout << "Default C called!\n"; } 
    C(const C &rhs) { cout << "CC called!\n"; } 
}; 

const C f() 
{ 
    cout << "Entered f()!\n"; 
    return C(); 
} 

int main() 
{ 
    C a = f(); 
    C b = a; 

    return 0; 
} 

la salida que recibo es:

Entered f()! 
Default C called! 
CC called! 

Desde f() está regresando por valor, que debe devolver un temporal. Como T a = x; es T a(x);, ¿no llamaría al constructor de copia para la construcción de a, con el pass-in temporal como argumento?

Respuesta

14

Dado que f() está regresando por valor, debe devolver un valor temporal. Como T a = x; es T a(x);, ¿no llamaría al constructor de copia para la construcción de a, con el pass-in temporal como argumento?

Buscar Optimización del valor de retorno. Esto está activado por defecto. Si utiliza Windows con MSVC 2005+, puede usar /Od para desactivarlo y obtener el resultado deseado (o -fno-elide-constructors en GCC). Además, para MSVC, consulte el artículo this.

12,8 objetos de clase copia

Cuando se cumplen ciertos criterios, se permite una implementación omitir la construcción copia de un objeto de clase, incluso si el constructor de copia y/o destructor para el objeto tiene efectos secundarios . En tales casos, la implementación trata el origen y objetivo de la operación de copia omitido maneras como simplemente dos diferentes de se refieren al mismo objeto, y la destrucción de ese objeto se produce en la última de las ocasiones en que los dos objetos tendrían destruido sin la optimización .115 se permite Esta elisión de las operaciones de copia en los siguientes circunstancias (que puede ser combinados para eliminar múltiples copias):

- en una instrucción de retorno en una función con un tipo de retorno de clase, cuando la expresión es el nombre de un objeto automática no volátil con el mismo tipo cv-calificada como el tipo de retorno función, la operación de copia se puede omitir por la construcción del objeto automática directamente en la función de re gire valor - en una banda expresión, cuando el operando es el nombre de un objeto automático no volátil, la operación copia desde el operando al objeto excepción (15.1) se puede omitir mediante la construcción de la automática oponerse directamente en el objeto de excepción

- cuando un objeto de clase temporal que no ha sido atado a una referencia (12.2) sería copiado a un objeto de clase con el mismo tipo cv-sin reservas, la copia la operación puede ser omitida por construir el objeto temporal directamente en el blanco de la copia omitido

- cuando el excepción-declaración de una excepción manejador (Cláusula 15) declara un objeto del mismo tipo (a excepción de cv-calificación) como el objeto de excepción (15.1), la operación de copia puede omitirse tratando la excepción-declaración como un alias para el objeto de excepción si el significado de el programa será sin cambios, excepto para la ejecución de los constructores y Destructores para el objeto declarado por la excepción-declaración.

Nota: El énfasis es mío

+0

Uso GCC, y con '-fno-elide-constructors' ¡mostró exactamente lo que está pasando debajo del capó! A veces estas optimizaciones confunden mucho a un alumno :) Sin embargo, estoy de acuerdo en que deberían estar activados por defecto, ya que de nuevo la creación de una persona desinformada se optimizará por defecto. – legends2k

+0

@ legends2k: RVO es demasiado útil para dejarlo a los caprichos de los usuarios.Además, este es uno de los pocos casos en que el estándar permite una optimización. Eso revitaliza por qué se deja encendido. Sin embargo, tenga en cuenta que esto no es cierto para otras optimizaciones en general. – dirkgently

+0

De acuerdo, punto tomado. – legends2k

4

Este es un ejemplo de Optimización del valor devuelto (RVO) características compatibles con su compilador.

Un constructor de copia podría no llamarse cuando devuelva por valor.

Utilice la opción -fno-elide-constructors en GCC para desactivar esa función.

+0

+1 para la respuesta rápida! – legends2k

2

creo que se llama return value optimization.

que asumen cuando f() vuelve C objeto, el objeto se asigna en el espacio de pila del método de llamada, por tanto, no se requiere copia para inicializar C a. Este es su default C called.

C b = a 

Esto provoca un constructor de copia de ahí su CC called.

Por cierto, el ejemplo en wiki se parece bastante a tu código.

+0

+1 para el enlace wiki. Oops! Incluso el nombre se parece, pero juro que no publiqué después de leer eso, estoy leyendo _Teniendo en C++ _ :) – legends2k

Cuestiones relacionadas