2012-09-07 13 views
17

Duplicar posible:
Lifetime of temporaries¿Cuándo salen los parámetros temporales de los valores?

int LegacyFunction(const char *s) { 
    // do something with s, like print it to standard output 
    // this function does NOT retain any pointer to s after it returns. 
    return strlen(s); 
} 

std::string ModernFunction() { 
    // do something that returns a string 
    return "Hello"; 
} 

LegacyFunction(ModernFunction().c_str()); 

El ejemplo anterior podría fácilmente ser reescrito para usar punteros inteligentes en lugar de cadenas; Me he encontrado con estas dos situaciones muchas veces. De todos modos, el ejemplo anterior construirá una cadena STL en ModernFunction, la devolverá, luego obtendrá un puntero a una cadena de estilo C dentro del objeto de cadena, y luego pasará ese puntero a la función heredada.

  1. Hay un objeto de cadena temporal que existe después de que ModernFunction ha regresado. ¿Cuándo sale fuera del alcance?
  2. ¿Es posible que el compilador llame a c_str(), destruya este objeto de cadena temporal y luego pase un puntero colgante a LegacyFunction? (Recuerde que el objeto de cadena gestiona la memoria a la que c_str() devuelve los valores de valor ...)
  3. Si el código anterior no es seguro, ¿por qué no es seguro y existe una forma mejor e igualmente concisa de escribir que agregar una variable temporal al hacer las llamadas a la función? Si es seguro, ¿por qué?
+0

Acabo de compilar esto y funcionó. También debería funcionar, según la respuesta de ForEveR. –

+2

@ H2CO3, "funcionó" nunca prueba nada, a veces solo tienes suerte. Si lo hubieras probado y * no * funcionado, eso sería diferente. –

+0

@MarkRansom notó que "también debería funcionar, según la respuesta de ForEveR"? (para aclarar: lo sé). –

Respuesta

14
LegacyFunction(ModernFunction().c_str()); 

Destrucción de copia será después de la evaluación de full expression (es decir, después del regreso de LegacyFunction).

n3337 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.

n3337 1,9/10

A-expresión completa es una expresión que no es una subexpresión de otra expresión. Si se define una construcción de lenguaje para producir una llamada implícita de una función, se considera que el uso de la construcción de lenguaje es una expresión a los fines de esta definición. Una llamada a un destructor generado al final de la vida útil de un objeto que no sea un objeto temporal es una expresión completa implícita. Las conversiones aplicadas al resultado de una expresión con el fin de satisfacer los requisitos de la construcción del lenguaje en el que aparece la expresión también se consideran parte de la expresión completa. [Ejemplo:

struct S { 
S(int i): I(i) { } 
int& v() { return I; } 
private: 
int I; 
}; 
S s1(1); // full-expression is call of S::S(int) 
S s2 = 2; // full-expression is call of S::S(int) 
void f() { 
if (S(3).v()) // full-expression includes lvalue-to-rvalue and 
// int to bool conversions, performed before 
// temporary is deleted at end of full-expression 
{ } 
} 

9

Hay un objeto de cadena temporal que existe después de ModernFunction ha regresado. ¿Cuándo sale fuera del alcance?

Estrictamente hablando, nunca es en alcance. El alcance es una propiedad de un nombre, no un objeto.Sucede que las variables automáticas tienen una asociación muy estrecha entre ámbito y de por vida. Los objetos que no son variables automáticas son diferentes.

Los objetos temporales se destruyen al final de la expresión completa en la que aparecen, con un par de excepciones que no son relevantes aquí. De todos modos, los casos especiales amplían la vida útil de los temporales, no los reducen.

¿Es posible que el compilador para llamar c_str(), destruct este objeto cadena temporal, y luego pasar una referencia colgante a LegacyFunction

No, porque la expresión completa es LegacyFunction(ModernFunction().c_str()) (excluyendo el punto y coma: siente esa pedantería), por lo que el temporal que es el valor de retorno de ModernFunction no se destruye hasta que LegacyFunction haya regresado.

Si es seguro, ¿por qué?

Porque la vida útil del temporal es lo suficientemente larga.

En general, con c_str, tiene que preocuparse por dos cosas. Primero, el puntero que devuelve se vuelve inválido si la cadena se destruye (que es lo que estás preguntando). En segundo lugar, el puntero que devuelve se vuelve inválido si la cadena se modifica. No te has preocupado por eso aquí, pero está bien, no es necesario, porque tampoco modifica la cadena.

Cuestiones relacionadas