2012-02-12 25 views
5

El código siguiente llama al destructor 4 veces:Valor devuelto Optimización - C++ - Destructor llama

#include<iostream> 
using namespace std; 

class A{ 
    public: 
    A(){cout<<"A"<<endl;} 
    ~A(){cout<<"~A"<<endl;} 
    A f(){cout<<"F"<<endl; A b; return b;} 
}; 

int main(){ 
    A a,b; 
    b=a.f(); 
} 

SALIDA:

A 
A 
F 
A 
~A 
~A 
~A 
~A 

Puede alguien explicar por favor? Estaba pensando que solo debería haber tres llamadas a destructor.

+0

No, no es así. http://ideone.com/ywGdo –

+0

¡Uy! Usé Codepad .. http://codepad.org/1OJGoYGP – Venky

+0

No etiquetes tus preguntas con "c" cuando se trata de C++. Los idiomas no son lo mismo. – tinman

Respuesta

1

Su compilador no lo optimizó. ¿Lo has compilado con las optimizaciones habilitadas?

Aquí está la salida del mismo código, compilado con gcc:

A 
A 
F 
A 
~A 
~A 
~A 
8

Hay dos objetos en main(), por lo que el destructor será llamado dos veces sólo a causa de ellos. Un objeto en f(), por lo que el destructor se llamará un tiempo solo por eso. Total 3 veces (que espera, pero sigue leyendo ...)

Ahora se llama a la cuarta vez destructor para el objeto temporal que se crea al regresar de f. Esto puede suceder solo cuando no hay ningún RVO. RVO es la elección del compilador, lo que significa que puede optimizarlo o no. El lenguaje no ofrece ninguna garantía de RVO.

De todos modos, solo aumente su nivel de optimización; Estoy seguro de que verá como máximo 3 invocaciones de destructor solamente.

0

No puede confiar en que se produzca RVO. Es por eso que nunca se debe poner la lógica funcional dentro de los destructores o los constructores de copia (sí, también se pueden eludir).

La optimización del valor de retorno es solo algo permitido por la norma, pero no se aplica.

Sin optimización u O2, también recibo 4 llamadas de destructor.

Con una optimización completa - buey - solo me dan 3.

+0

/O2 también contiene NRVO, lo que significa que solo se llaman 3 destructores. Compruebe http://msdn.microsoft.com/en-us/library/8f8h5cxt.aspx. – LihO

+0

@LihO Probé el código. Así que supongo que hay un error en MSVS, si lo que dices es exacto. –

+0

También lo probé (MSVS2010). Con la optimización deshabilitada ('/ Od') se llaman 4 destructores. Con '/ O1' o'/O2', se llaman 3 destructores. – LihO

1

Hay una creación oculto y la destrucción de una instancia de A: cuando se está volviendo de la función f(), se crea una copia temporal del objeto b. Se asigna a b en main() y luego se destruye.

+0

Está preguntando por qué no ocurre RVO. –

+0

@Luchian Tiene razón, pero como no mencionó los niveles de optimización utilizados (o no), estaba bajo la impresión de que simplemente pasó por alto ese factor temporal cuando regresaba por valor. –

0

La variable local en f se copia en una variable temporal cuando la función retorna. Es por eso que hay cuatro llamadas al destructor. (Operación de copia llama al constructor de copia A(A&) no el constructor por defecto A(), por lo tanto, tres A s.)

+0

Esa no es la pregunta. Él pregunta por qué la optimización del valor de retorno no se aplica. –

+0

No estoy seguro de que él o ella esté al tanto de RVO. La pregunta es simplemente "¿Por qué hay cuatro llamadas de destructor en lugar de tres?" Yo respondí eso. –

+0

¿Has leído el título? –

3

Existen 2 objetos en principal: A a,b;, un objetivo en el cuerpo de la función f(): A b; y luego hay objeto temporal que se está copiando y su copia está almacenada en b.

Al regresar b en el cuerpo de su función, la copia se crea en un primer momento, entonces el local de b se destruye, luego copia se asigna a la variable declarada en b principal y luego se destruye esta copia.

Agregue la línea siguiente a la clase A definición y verse a sí mismo:

A(const A&) { cout << "copying" << endl; } 

Con Named Return Value Optimization, el compilador trata de eliminar redundante constructor de copia y Destructor llama lo que significa que los entes locales b de la función f() se le asignará en la variable b en main sin crear una copia. Entonces con RVO/NRVO solo se crean 3 objetos en su caso.

Aunque hay una manera de cómo evitar la autodestrucción esta copia sin RVO en su caso:

A a; 
A b = a.f(); 

en este caso copia del valor de retorno de la función f() se crea y se almacena como una variable b. Lo que también significa que no se llama a ningún operador de asignación y solo se crean 2 objetos en main: a y copia de b devuelto por f().

Espero que esto ayude.

Cuestiones relacionadas