2010-02-19 5 views
14

El siguiente código imprime uno, dos, tres. ¿Es eso deseado y cierto para todos los compiladores de C++?¿Por qué se destruyen los objetos sin nombre de C++ antes de que finalice el bloque del osciloscopio?


class Foo 
{ 
     const char* m_name; 
public: 
     Foo(const char* name) : m_name(name) {} 
     ~Foo() { printf("%s\n", m_name); } 
}; 

void main() 
{ 
     Foo foo("three"); 
     Foo("one"); // un-named object 
     printf("two\n"); 
} 
+0

Duplicado: http://stackoverflow.com/questions/1388685/local-variable-scope-question –

Respuesta

33

Una variable temporal vive hasta el final de la expresión completa en la que se creó. La suya termina en el punto y coma.

Esto está en 12.2/3:

objetos temporales se destruyen como el último paso en la evaluación de la expresión completa (1.9) que (léxico) contiene el punto en el que fueron creados.

Su comportamiento está garantizado.

Hay dos condiciones que, si se cumplen, extenderán la vida útil de un temporal. El primero es cuando se trata de un inicializador para un objeto. El segundo es cuando una referencia se une a un temporal.

+3

... a menos que se cumplan las condiciones de 12.2/4, lo que puede extender aún más la vida útil de un temporal. – AnT

+0

@AndreyT: Er, sí. Supongo que puede ser importante mencionarlo. – GManNickG

+1

Puede que no sea importante mencionarlo en el contexto de la pregunta original. Pero después de leer su aseveración explícita que dice que "la vida útil de una variable temporal está activa cuando termina la expresión", pensé que era algo que valga la pena mencionar. – AnT

6

El alcance de un objeto temporal como ese es solo una línea. Piénselo, ya no puede hacer referencia a él una vez que la línea termina, entonces, ¿por qué el objeto se mantendrá?

Si este no fuera el caso, los compiladores no podrían optimizar los objetos temporales en las llamadas a funciones.

3

Sí, es deseado.

Foo foo("three") crea un objeto normal que se destruirá cuando finalice el alcance.

Foo("one") crea un objeto temporal, que se destruye al final de la instrucción [1]. ¿Por qué? Porque no hay forma de que pueda acceder una vez que la instrucción haya finalizado.

[1] Simplificación deliberada: Debería haber dicho punto de secuencia.

+9

El punto de secuencia no tiene nada que ver con esto. La duración de los temporales termina al final de la expresión completa, incluso si hay un punto de secuencia al final de la "instrucción" que creó el objeto. Por ejemplo, en 'Foo (" a "), Foo (" b "), Foo (" c ");' se garantiza que los tres temporarios vivirán hasta el final del enunciado, aunque haya puntos de secuencia en el medio . – AnT

11

Las reglas que rigen la vida útil de los objetos temporales no tienen nada que ver con la noción de alcance . El ámbito es una propiedad de un nombre, y los objetos temporales no tienen nombres. En otras palabras, los objetos temporales no tienen alcance.

La mayor parte del tiempo la vida útil de un objeto temporal finaliza al final de la expresión completa que creó ese objeto, que es lo que observó en su experimento. Esta es la regla general que tiene algunas excepciones. La principal es que si adjunta inmediatamente una referencia a su objeto temporal, el tiempo de vida del objeto se ampliará para que coincida con el tiempo de vida de la referencia

const Foo &rfoo = Foo("one"); 

Lo anterior será temporal vivir hasta rfoo vidas.

+0

+1 'El alcance es una propiedad de un nombre, y los objetos temporales no tienen nombres. ¿El tiempo de vida de la extensión temporal se vincula a una referencia sin el calificador' const'? 'Foo & rfoo = Foo (" uno ");' – Mahesh

+0

Leí que el tiempo de vida de temporal solo puede extenderse vinculando a una referencia 'const'. Pero el ejemplo http://ideone.com/nTVPZ funciona bien en VS 2010 pero no en gcc (también el 'this' en ambos casos es el mismo en el enlace dado que significa la extensión de la vida temporal incluso sin el calificador' const' en VS). Es gcc o VS correcto aquí? – Mahesh

+0

@Mahesh: el código no es compilable en C++ estándar, por lo que GCC lo rechaza. VS lo acepta como una extensión solo porque tiene extensiones habilitadas. Si deshabilita las extensiones de idioma en VS, el código no se compilará en VS también. – AnT

0

Porque el comité de normas cometió errores. Lo hace porque eligieron hacerlo hacerlo. Está definido para hacerlo de esta manera. Debe considerarse una instancia anónima con alcance igual que si hubiera sido nombrado. Desde el punto de instanciación hasta el final del bloque. Al parecer, pensaron que el único uso era pasar los temporales a funciones en las que se empujaban en la pila y salían de la pila al final de una llamada de función ...

Un objeto sin nombre todavía debe ser empujado a la pila y permanecer en la pila hasta que el bloque termine, saliéndolo de la pila cuando se espera. Construir y destruir un objeto durante una sola declaración no tiene sentido. Me gustaría ver una sola instancia/caso donde esto sea realmente útil. Si no permanece en el alcance durante la duración del bloqueo, sin duda debería ser un error y, como mínimo, debería generar una advertencia.

+1

Hablar explícitamente de la pila es innecesario; es perfectamente posible tener una implementación utilizable de C++ que no use la pila en absoluto y en su lugar asigna todo en ubicaciones estáticas. También es posible que se pasen pequeños valores temporales en los registros, no en la memoria direccionable. –

+1

"Construir y destruir un objeto durante una sola declaración no tiene sentido". No si lo haces por los efectos secundarios o en una cadena de conversión. Es tan útil un gran proyecto de C++ como que Firefox podría tener miles de estos constructos por todas partes. Son * inmensamente * útiles. Sería bastante malo si estos objetos se mantuvieran hasta el final del bloque, la presión de la memoria caché mataría el rendimiento de muchos proyectos, incluso si el uso general de la memoria no cambiara significativamente. –

Cuestiones relacionadas