2012-09-11 12 views
28

Duplicar posible:
Structure of a C++ Object in Memory Vs a Struct
memory layout c++ objects¿Cómo se ve un objeto en la memoria?

Esta es probablemente una pregunta muy tonta, pero yo le pedirá de todos modos. Tengo curiosidad por cómo se ve un objeto en la memoria. Obviamente, debería tener todos sus datos de miembro. Supongo que las funciones para un objeto no se duplicarían en la memoria (¿o quizás estoy equivocado?). Parecería un desperdicio tener 999 objetos en la memoria, todos con la misma función definida una y otra vez. Si solo hay 1 función en la memoria para los 999 objetos, entonces, ¿cómo sabe cada función que los datos de los miembros se pueden modificar (específicamente quiero saber en el nivel bajo). ¿Hay un puntero de objeto que se envía a la función detrás de las escenas? Tal vez es diferente para cada compilador?

Además, ¿cómo afecta la palabra clave estática esto? Con los datos de los miembros estáticos, creo que los 999 objetos usarían la misma ubicación de memoria para sus datos de miembros estáticos. ¿Dónde se almacena esto? Las funciones estáticas supongo que también serían solo un lugar en la memoria, y no tendrían que interactuar con objetos instanciados, lo que creo que entiendo.

+6

Esta es una buena pregunta – Coffee

+4

Esta es una pregunta ** muy ** interesante, pero creo que se responde aquí: http://stackoverflow.com/questions/1632600/memory-layout-c-objects y aquí: http : //stackoverflow.com/questions/422830/structure-of-ac-object-in-memory-vs-a-struct – fableal

+5

Uhm ... como un grupo de 0 y 1 ... –

Respuesta

14

Los miembros de la clase estática se tratan casi exactamente como variables/funciones globales. Debido a que no están vinculados a una instancia, no hay nada que discutir sobre el diseño de la memoria.

Las variables de clase se duplican para cada instancia como se puede imaginar, ya que cada instancia puede tener sus propios valores únicos para cada variable miembro.

Clase miembro funciones solo existen una vez en un segmento de código en la memoria. En un nivel bajo, son como funciones globales normales pero reciben un puntero a this. Con Visual Studio en x86, es a través de ecx registrarse usando la convención de llamadas thiscall.

Cuando hablamos de funciones virtuales, polimorfismo, el diseño de la memoria se vuelve más complicado, introduciendo un "vtable" que es básicamente un conjunto de punteros de funciones que definen la topografía de la instancia de clase.

+2

Para ser pedante, las funciones miembro no "reciben un puntero a' this' ". Más bien, es al revés. Las funciones miembro tienen un argumento de instancia implícita, y dentro del cuerpo de la función, 'this' es un puntero a esa instancia. –

+1

Incluso con esa descripción, sigue siendo correcto decir que la función recibe el puntero 'this'. Es un argumento pasado a través de 'ecx' en oposición a la pila. O tal vez no te entendí. – tenfour

+0

Es solo un atajo mental común que ocasiona problemas a las personas más adelante cuando intentan comprender la resolución de sobrecarga de la función miembro. No es estrictamente importante aquí, pero pensé que debo señalar la forma en que el lenguaje define las funciones de los miembros. –

0

Contará con sus variables miembro, y también una tabla de funciones virtuales si es polimórfica, que incluirá una lista de punteros a las funciones con las que están asociados sus métodos virtuales.

Estático significa solo una copia.

+0

Normalmente, cada objeto no contiene una tabla de punteros a función, pero un puntero (para cada subtipo polimórfico) a una tabla. Las tablas mismas se comparten entre todos los objetos del mismo tipo dinámico, guardando memoria. Y las tablas contienen más que solo punteros de función, también requieren el ajuste entre un puntero de subtipo y el tipo de puntero esperado para el parámetro 'this' oculto de la función. –

3

lo solicitado algunas preguntas aquí ...

Disposición

Todos los miembros no estáticos se organizan en memoria al igual que una estructura. Puede haber acolchado si el compilador decide poner ninguna. Si usted tiene una gran variedad de objetos, es como una gran variedad de estructuras

Los miembros estáticos

se almacenan por separado, obviamente. Una copia.

Las llamadas a funciones

Hay un poco de magia pasando detrás de las escenas para las clases. Cuando llama a una función miembro es muy similar a cualquier otra función, excepto que tiene una convención de llamada diferente. Efectivamente, esto inserta el puntero del objeto (esto) en la lista de parámetros.

[editar : el código de la función en sí no se almacena con el objeto - esto le permite hacer cosas divertidas como delete this y continuando la ejecución de una función miembro siempre y cuando ya no se accede al objeto que acaba de eliminar] .

Cuando tiene funciones sobrecargadas o polimórficas, las cosas se vuelven un poco más mágicas. This article es una explicación que busqué en Google en aproximadamente 5 segundos. Estoy seguro de que hay muchos más. Nunca me he preocupado demasiado por el funcionamiento interno de las llamadas a objetos, pero siempre es bueno saberlo.

Debe intentar hacer una clase que muestre todos estos aspectos diferentes y observar el conjunto generado en cada caso. Lo he hecho antes cuando sintonicé algún código de tiempo crítico.

1

Como sospecha, los miembros (campos) de datos se presentan secuencialmente. Esto también incluye los campos de clases base.

Si la clase (o una de sus clases base) contiene algún método virtual, el diseño generalmente comienza con vptr, es decir, un puntero a una tabla virtual (o vtable) que es una tabla de punteros para implementar funciones relacionadas con ese clase. Tenga en cuenta que esto no está definido por estándar, pero AFAIK todos los compiladores actuales utilizan este enfoque. Además, con la herencia múltiple se pone más peluda, así que ignórelo por el momento.

+-----------+ 
| vptr  | pointer to vtable which is located elsewhere 
+-----------+ 
| fieldA | first member 
| fieldB | ... 
| fieldC | 
| ...  | 
+-----------+ 

campos que puede tomar más espacio, entonces la suma de sus tamaños individuales, que depende de embalaje (por ejemplo, 1 embalaje byte asegura que no hay huecos, pero es menos eficiente que el embalaje 4 o 8 bytes con respecto al rendimiento)

Las funciones miembro (no estáticas) reciben el puntero al objeto, generalmente mediante el registro ecx en la arquitectura x86. Esto tampoco está definido por el estándar.

Las funciones estáticas son similares a las funciones globales, y operan en campos de clases estáticas (compartidas para todas las instancias de una clase) que se ubican en el segmento de datos.

3

Lo primero a tener en cuenta es que en C++ el término "objeto" incluye cosas como enteros.

Lo siguiente es que las estructuras se diseñan de forma muy similar a como se esperaría. Un miembro sigue al siguiente en la memoria con una cantidad indefinida de relleno entre.

Cuando una clase hereda de otra, la clase comenzará con su clase base, que a su vez puede comenzar con una clase base propia. Por lo tanto, Derived * y Base * tendrán el mismo valor en los casos de herencia individual. Siguiendo el área de la base (sus miembros) serán los miembros de la clase derivados a su vez, con una cantidad indefinida de relleno entre ellos.

Cuando una clase hereda de más de una base, las cosas se vuelven un poco diferentes. Las áreas de base se presentan en la memoria de forma secuencial. Base1 seguido de Base2, etc ... después de lo cual los miembros de la clase derivada se distribuyen a su vez con una cantidad indefinida de relleno entre ellos.

Si el objeto es de una clase POD, se garantiza que el primer miembro de la clase estará en la ubicación en la memoria donde reside el objeto. Esto significa que Class * y Class-> firstMember * tendrán el mismo valor. No creo que esto se aplique a entidades que no sean POD.

En el caso de las clases polimórficas, aquellas con funciones virtuales, se creará un miembro secreto adicional denominado vtable. Esto no está garantizado por nada en el estándar, pero es prácticamente la única forma de hacerlo y sigue las reglas que lo son. Cada clase tiene esto, así que si tu clase tiene bases, entonces tendrá su tabla y tendrás la tuya para funciones adicionales.

Todas las funciones miembro tendrán sus nombres destrozados y los parámetros modificados para aceptar this como primer argumento. Esto sucede detrás de escena mientras el compilador construye cosas. Las funciones virtuales serán señaladas por el vtable. Los no virtuales simplemente se resolverán estáticamente y se usarán directamente.

Los miembros estáticos no son miembros del objeto creado por una clase. Un miembro estático es simplemente una variable global con diferente alcance.

Cuestiones relacionadas