C++ Copia constructor, temporarias y copia semántica.
variable-assignment copy-constructor (3)
Para este programa
#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 obtengo es:
Entered f()!
Default C called!
CC called!
Como f()
está devolviendo por valor, debería 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 temporal pasado como su argumento?
Como
f()
está devolviendo por valor, debería devolver un temporal. ComoT a = x;
esT a(x);
, ¿no llamaría al constructor de copia para la construcción dea
, con el temporal pasado como su argumento?
Busque la optimización del valor de retorno. Esto está activado de forma predeterminada. Si está usando Windows con MSVC 2005+, puede usar /Od
para desactivarlo y obtener el resultado deseado (o -fno-elide-constructors
en GCC). Además, para MSVC ver this artículo.
12.8 Copiar objetos de clase
15 Cuando se cumplen ciertos criterios, una implementación puede omitir la construcción de copia de un objeto de clase, incluso si el constructor y / o destructor de copia del objeto tiene efectos secundarios. En tales casos, la implementación trata el origen y el destino de la operación de copia omitida simplemente como dos formas diferentes de referirse al mismo objeto, y la destrucción de ese objeto ocurre en el último momento en que los dos objetos hubieran sido destruidos sin la optimización.115 Esta elección de operaciones de copia está permitida en las siguientes circunstancias (que pueden combinarse para eliminar múltiples copias):
- en una declaració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ático no volátil con el mismo tipo no cualificado de CV que el tipo de retorno de función, la operación de copia se puede omitir construyendo el automático objeto directamente en el valor de retorno de la función: en una expresión de lanzamiento, cuando el operando es el nombre de un objeto automático no volátil, la operación de copia del operando al objeto de excepción (15.1) se puede omitir construyendo el objeto automático directamente en el objeto de excepción
- cuando un objeto de clase temporal que no se ha vinculado a una referencia (12.2) se copiaría a un objeto de clase con el mismo tipo no cualificado cv, la operación de copia se puede omitir construyendo el objeto temporal directamente en el destino de los omitidos dupdo
- cuando la declaración de excepción de un controlador de excepciones (Cláusula 15) declara un objeto del mismo tipo (excepto para la calificación cv) que el objeto de excepción (15.1), la operación de copia se puede omitir tratando la declaración de excepción como una alias para el objeto de excepción si el significado del programa no cambia, excepto por la ejecución de constructores y destructores para el objeto declarado por la declaración de excepción.
Nota: Énfasis mío.
Este es un ejemplo de las funciones de optimización de valor de retorno (RVO) que admite su compilador.
Es posible que no se llame a un constructor de copia cuando se devuelve por valor.
Use la -fno-elide-constructors
en GCC para desactivar esa función.
Creo que se llama optimización de valor de retorno .
Supongo que cuando f()
devuelve el objeto C
el objeto se asigna en el espacio de pila del método de llamada, por lo que no se requiere una copia para inicializar C a
. Esta es tu default C called
.
C b = a
Esto causa un constructor de copia por lo tanto su CC called
.
Por cierto, el ejemplo en wiki se parece bastante a tu código.