c++ - para - manual de programacion android pdf
¿Dónde está almacenado el puntero "este" en la memoria de la computadora? (6)
La forma más fácil es pensar en this
como un argumento adicional oculto que siempre se pasa automáticamente.
Entonces, un método de ficción como:
size_t String::length(void) const
{
return strlen(m_string);
}
en realidad es más como esto bajo el capó:
size_t String__length(const String *this)
{
return strlen(this->m_string);
}
y una llamada como:
{
String example("hello");
cout << example.length();
}
se convierte en algo así como:
cout << String__length(&example);
Tenga en cuenta que la transformación anterior se simplifica, con suerte para aclarar mi punto. No es necesario completar los comentarios con "whaaa, ¿dónde está la clasificación para la sobrecarga de métodos, eh?" - escriba objeción, por favor. :)
Eso transforma la pregunta en "¿dónde se almacenan los argumentos?", Y la respuesta es, por supuesto, "depende". :)
A menudo está en la pila, pero también puede estar en registros, o cualquier otro mecanismo que el compilador considere que es bueno para la arquitectura de destino.
¿Dónde exactamente está almacenado el puntero "este" en la memoria? ¿Está asignado en la pila, en el montón o en el segmento de datos?
#include <iostream>
using namespace std;
class ClassA
{
int a, b;
public:
void add()
{
a = 10;
b = 20;
cout << a << b << endl;
}
};
int main()
{
ClassA obj;
obj.add();
return 0;
}
En el código anterior, estoy llamando a la función miembro add()
y el objeto receptor se pasa implícitamente como el puntero ''this''. ¿Dónde está this
almacenado en la memoria?
Otras respuestas han sido muy útiles para explicar cómo un compilador típico implementa this
(al pasarlo como un primer parámetro implícito a la función).
Creo que también es útil ver lo que la especificación ISO de C ++ dice explícitamente sobre esto. De acuerdo con la especificación C ++ 03 ISO, §9.3.2 / 1:
En el cuerpo de una función miembro no estática (9.3), la palabra clave
this
es una expresión non-lvalue cuyo valor es la dirección del objeto para el que se llama a la función.
Es importante tener en cuenta que this
no es una variable, es una expresión , del mismo modo que la expresión 1 + 2 * 3
es una expresión. El valor de esta expresión se puede almacenar prácticamente en cualquier lugar. El compilador puede ponerlo en la pila y pasarlo como un parámetro implícito a una función, o puede ponerlo en un registro, y es concebible que pueda ponerlo en el montón o en el segmento de datos. La especificación C ++ deliberadamente le da a la implementación cierta flexibilidad aquí.
Creo que la respuesta del "abogado de idiomas" es "esto está completamente definido por la implementación, y además this
técnicamente no es un puntero, sino una expresión que se evalúa como un puntero".
¡Espero que esto ayude!
this
comporta principalmente como un argumento de función, y como tal se almacenará en la pila o, si las convenciones de llamada binarias de la arquitectura lo permiten, en un registro.
this
es un valor r (no se puede tomar su dirección), por lo que no ocupa (necesariamente) memoria. Según el compilador y la arquitectura de destino, a menudo estará en un registro: i0 en Sparc, ECX con MSVC en Intel, etc. Cuando el optimizador está activo, puede incluso moverse. (Lo he visto en diferentes registros con MSVC).
this
generalmente se pasa como un argumento oculto del método (la única diferencia entre las diferentes convenciones de llamadas es cómo ).
Si llamas:
myClass.Method(1, 2, 3);
El compilador genera el siguiente código:
Method(&myClass, 1, 2, 3);
Donde el primer parámetro es realmente el puntero a this
.
Revisemos el siguiente código:
class MyClass
{
private:
int a;
public:
void __stdcall Method(int i)
{
a = i;
}
};
int main(int argc, char *argv[])
{
MyClass myClass;
myClass.Method(5);
return 0;
}
Al usar __stdcall
al compilador a pasar todos los parámetros a través de la pila. Si luego inicia el depurador e inspecciona el código ensamblador, encontrará algo como lo siguiente:
myClass.Method(5);
00AA31BE push 5
00AA31C0 lea eax,[myClass]
00AA31C3 push eax
00AA31C4 call MyClass::Method (0AA1447h)
Como puede ver, el parámetro del método se pasa a través de la pila, luego la dirección de myClass se carga en el registro eax y nuevamente se inserta en la pila. En otras palabras, this
se trata como un parámetro regular de este método.
this
no se almacena en una ubicación bien definida! El objeto al que apunta se almacena en alguna parte, y tiene una dirección bien definida, pero la dirección en sí misma no tiene una dirección de hogar específica. Se comunica en el programa. No solo eso, sino que puede haber muchas copias de ese puntero.
En la siguiente función de init
imaginaria, el objeto se registra a sí mismo para recibir eventos y devoluciones de llamada del temporizador (utilizando objetos fuente de eventos imaginarios). Entonces, después del registro, hay dos copias adicionales de this
:
void foo_listener::init()
{
g_usb_events.register(this); // register to receive USB events
g_timer.register(this, 5); // register for a 5 second timer
}
En una cadena de activación de funciones, también habrá múltiples copias de este puntero. Supongamos que tenemos un objeto obj
y llamamos a su función foo
. Esa función llama a la función de bar
del mismo objeto, y la bar
llama a otra función llamada update
. Cada nivel de activación de función tiene this
puntero. Se almacena en un registro de máquina, o en una ubicación de memoria en el marco de pila de la activación de función.