Las temporarias tienen almacenamiento. Se asignan en la pila de la persona que llama (nota: podrían ser objeto de convención de llamada, pero creo que la pila todo el uso de la persona que llama):
caller()
{
callee1(Tmp());
callee2(Tmp());
}
compilador asignar espacio para el resultado Tmp()
en la pila de la caller
. Puede tomar la dirección de esta ubicación de memoria: será una dirección en la pila del caller
.Lo que el compilador no garantiza es que conservará los valores en esta dirección de pila después de callee
devuelve. Por ejemplo, el compilador puede colocar allí otra temporal, etc.
EDIT: Creo, que ha anulado para eliminar código como este:
T bar();
T * ptr = &bar();
, ya que es muy probable que conducen a problemas.
EDIT: aquí hay una little test: GCC
#include <iostream>
typedef long long int T64;
T64 ** foo(T64 * fA)
{
std::cout << "Address of tmp inside callee : " << &fA << std::endl;
return (&fA);
}
int main(void)
{
T64 lA = -1;
T64 lB = -2;
T64 lC = -3;
T64 lD = -4;
T64 ** ptr_tmp = foo(&lA);
std::cout << "**ptr_tmp = *(*ptr_tmp) = lA\t\t\t\t**" << ptr_tmp << " = *(" << *ptr_tmp << ") = " << **ptr_tmp << " = " << lA << std::endl << std::endl;
foo(&lB);
std::cout << "**ptr_tmp = *(*ptr_tmp) = lB (compiler override)\t**" << ptr_tmp << " = *(" << *ptr_tmp << ") = " << **ptr_tmp << " = " << lB << std::endl
<< std::endl;
*ptr_tmp = &lC;
std::cout << "Manual override" << std::endl << "**ptr_tmp = *(*ptr_tmp) = lC (manual override)\t\t**" << ptr_tmp << " = *(" << *ptr_tmp << ") = " << **ptr_tmp
<< " = " << lC << std::endl << std::endl;
*ptr_tmp = &lD;
std::cout << "Another attempt to manually override" << std::endl;
std::cout << "**ptr_tmp = *(*ptr_tmp) = lD (manual override)\t\t**" << ptr_tmp << " = *(" << *ptr_tmp << ") = " << **ptr_tmp << " = " << lD << std::endl
<< std::endl;
return (0);
}
Programa de salida:
Address of tmp inside callee : 0xbfe172f0
**ptr_tmp = *(*ptr_tmp) = lA **0xbfe172f0 = *(0xbfe17328) = -1 = -1
Address of tmp inside callee : 0xbfe172f0
**ptr_tmp = *(*ptr_tmp) = lB (compiler override) **0xbfe172f0 = *(0xbfe17320) = -2 = -2
Manual override
**ptr_tmp = *(*ptr_tmp) = lC (manual override) **0xbfe172f0 = *(0xbfe17318) = -3 = -3
Another attempt to manually override
**ptr_tmp = *(*ptr_tmp) = lD (manual override) **0xbfe172f0 = *(0x804a3a0) = -5221865215862754004 = -4
La salida del programa de VC++:
Address of tmp inside callee : 00000000001EFC10
**ptr_tmp = *(*ptr_tmp) = lA **00000000001EFC10 = *(000000013F42CB10) = -1 = -1
Address of tmp inside callee : 00000000001EFC10
**ptr_tmp = *(*ptr_tmp) = lB (compiler override) **00000000001EFC10 = *(000000013F42CB10) = -2 = -2
Manual override
**ptr_tmp = *(*ptr_tmp) = lC (manual override) **00000000001EFC10 = *(000000013F42CB10) = -3 = -3
Another attempt to manually override
**ptr_tmp = *(*ptr_tmp) = lD (manual override) **00000000001EFC10 = *(000000013F42CB10) = 5356268064 = -4
Aviso, tanto GCC y reserva VC++ en la pila de main
variables locales ocultas para los temporales y MIGHT silenciosamente usalos, usalos a ellos. Todo va normal, hasta la última anulación manual: después de la última anulación manual tenemos una llamada adicional adicional al std::cout
. Usa el espacio de la pila donde simplemente escribimos algo, y como resultado obtenemos basura.
Línea inferior: tanto GCC como VC++ asignan espacio para los temporales en la pila del llamador. Podrían tener diferentes estrategias sobre cuánto espacio asignar, cómo reutilizar este espacio (también podría depender de las optimizaciones). Ambos pueden reutilizar este espacio a su discreción y, por lo tanto, no es seguro tomar la dirección de un temporal, ya que podríamos tratar de acceder a través de esta dirección el valor que asumimos que todavía tiene (por ejemplo, escribir algo allí directamente y luego intentar para recuperarlo), mientras que el compilador podría haberlo reutilizado y sobrescribir nuestro valor.
** relacionados: ** http://stackoverflow.com/questions/4301179/why-is-taking-the-address-of-a-temporary-illegal (aunque no estoy totalmente convencido de que es la misma) –
una de las respuestas más épicas en SO se aplica muy bien a su pregunta: [¿Se puede acceder a la memoria de una variable local fuera de su alcance?] (Http://stackoverflow.com/a/6445794/1025391) – moooeeeep
MSVS puede haga las extensiones de lenguaje que desee. Estoy de acuerdo contigo en que es extraño, sin embargo. –