diseño de memoria objetos C ++

Básicamente me pregunto cómo C ++ establece el objeto en la memoria. Entonces, escuché que los moldes dynamics simplemente ajustan el puntero del objeto en la memoria con un desplazamiento; y reinterpretar tipo de nos permite hacer cualquier cosa con este puntero. Realmente no entiendo esto. Los detalles serán apreciados!

Cada clase establece sus miembros de datos en el orden de statement.
El comstackdor puede colocar relleno entre los miembros para hacer que el acceso sea eficiente (pero no está permitido reordenar).

Cómo funciona dynamic_cast<> es un detalle de implementación del comstackdor y no está definido por el estándar. Todo dependerá de la ABI utilizada por el comstackdor.

reinterpret_cast<> funciona simplemente cambiando el tipo de objeto. Lo único que puede garantizar que funcione es lanzar un puntero a un vacío * y de regreso al mismo, el puntero a clase le dará el mismo puntero.

El diseño de la memoria se deja principalmente a la implementación. La excepción clave es que las variables miembro para un especificador de acceso dado estarán en orden de su statement.

§ 9.2.14

Los miembros de datos no estáticos de una clase (sin unión) con el mismo control de acceso (cláusula 11) se asignan para que los miembros posteriores tengan direcciones más altas dentro de un objeto de clase. El orden de asignación de los miembros de datos no estáticos con diferente control de acceso no está especificado (11). Los requisitos de alineación de implementación pueden causar que dos miembros adyacentes no se asignen inmediatamente después uno del otro; también pueden haber requisitos de espacio para gestionar funciones virtuales (10.3) y clases base virtuales (10.1).

Además de las variables miembro, una clase o estructura necesita proporcionar espacio para variables miembro, subobjetos de clases base, administración de funciones virtuales (por ejemplo, una tabla virtual), y relleno y alineamiento de estos datos. Esto depende de la implementación, pero la especificación Itanium ABI es una opción popular. gcc y clang se adhieren a ella (al menos hasta cierto punto).

http://mentorembedded.github.io/cxx-abi/abi.html#layout

El Itanium ABI por supuesto no es parte del estándar C ++ y no es vinculante. Para obtener más detalles, debe consultar la documentación y las herramientas de su implementador. clang proporciona una herramienta para ver el diseño de la memoria de las clases. Como ejemplo, lo siguiente:

 class VBase { virtual void corge(); int j; }; class SBase1 { virtual void grault(); int k; }; class SBase2 { virtual void grault(); int k; }; class SBase3 { void grault(); int k; }; class Class : public SBase1, SBase2, SBase3, virtual VBase { public: void bar(); virtual void baz(); // virtual member function templates not allowed, thinking about memory // layout and vtables will tell you why // template // virtual void quux(); private: int i; char c; public: float f; private: double d; public: short s; }; class Derived : public Class { virtual void qux(); }; int main() { return sizeof(Derived); } 

Después de crear un archivo fuente que utiliza el diseño de la memoria de la clase, clang revelará el diseño de la memoria.

 $ clang -cc1 -fdump-record-layouts layout.cpp 

El diseño para Class :

 *** Dumping AST Record Layout 0 | class Class 0 | class SBase1 (primary base) 0 | (SBase1 vtable pointer) 8 | int k 16 | class SBase2 (base) 16 | (SBase2 vtable pointer) 24 | int k 28 | class SBase3 (base) 28 | int k 32 | int i 36 | char c 40 | float f 48 | double d 56 | short s 64 | class VBase (virtual base) 64 | (VBase vtable pointer) 72 | int j | [sizeof=80, dsize=76, align=8 | nvsize=58, nvalign=8] 

Se puede encontrar más información sobre esta característica de clang en el blog de Eli Bendersky:

http://eli.thegreenplace.net/2012/12/17/dumping-ac-objects-memory-layout-with-clang/

gcc proporciona una herramienta similar, `-fdump-class-hierarchy ‘. Para la clase dada arriba, imprime (entre otras cosas):

 Class Class size=80 align=8 base size=58 base align=8 Class (0x0x141f81280) 0 vptridx=0u vptr=((& Class::_ZTV5Class) + 24u) SBase1 (0x0x141f78840) 0 primary-for Class (0x0x141f81280) SBase2 (0x0x141f788a0) 16 vptr=((& Class::_ZTV5Class) + 56u) SBase3 (0x0x141f78900) 28 VBase (0x0x141f78960) 64 virtual vptridx=8u vbaseoffset=-24 vptr=((& Class::_ZTV5Class) + 88u) 

No detalla las variables miembro (o al menos no sé cómo hacerlo) pero se puede decir que tendrían que estar entre el desplazamiento 28 y 64, al igual que en el diseño clang.

Puedes ver que una clase base se destaca como primary . Esto elimina la necesidad de ajustar this puntero cuando se accede a Class como SBase1 .

El equivalente de gcc es:

 $ g++ -fdump-class-hierarchy -c layout.cpp 

El equivalente para Visual C ++ es:

 cl main.cpp /c /d1reportSingleClassLayoutTest_A 

ver: https://blogs.msdn.microsoft.com/vcblog/2007/05/17/diagnosing-hidden-odr-violations-in-visual-c-and-fixing-lnk2022/

La respuesta es “es complicado”. La conversión dinámica no ajusta simplemente los punteros con un desplazamiento; en realidad puede recuperar punteros internos dentro del objeto para hacer su trabajo. GCC sigue un ABI diseñado para Itanium pero implementado de manera más amplia. Puede encontrar los detalles sangrientos aquí: Itanium C ++ ABI .

Como se indicó anteriormente, los detalles completos son complicados, dolorosos de leer, y realmente solo son útiles para los desarrolladores de comstackdores, y varían entre comstackdores. Básicamente, cada objeto contiene lo siguiente (generalmente distribuido en este orden):

  1. Información del tipo de tiempo de ejecución
  2. Objetos base no virtuales y sus datos (probablemente en orden de statement).
  3. Variables de miembros
  4. Objetos base virtuales y sus datos (Probablemente en alguna orden de búsqueda de árbol DFS).

Estos datos pueden rellenarse o no para facilitar la alineación de la memoria, etc. En el tipo de tiempo de ejecución, la información está oculta sobre el tipo, las tablas v para las clases principales virtuales, etc., todas ellas específicas del comstackdor.

En lo que respecta a los moldes, reinterpret_cast simplemente cambia el tipo de datos C ++ del puntero y no hace nada más, por lo que es mejor que se asegure de saber lo que está haciendo cuando lo usa, de lo contrario, es probable que estropee las cosas. dynamic_cast hace casi lo mismo que static_cast (al alterar el puntero), excepto que usa la información del tipo de tiempo de ejecución para determinar si puede convertirse al tipo dado y cómo hacerlo. De nuevo, todo eso es específico del comstackdor. Tenga en cuenta que no se puede dynamic_cast un void* porque necesita saber dónde encontrar la información del tipo de tiempo de ejecución para que pueda hacer todas sus maravillosas comprobaciones de tiempo de ejecución.

esta pregunta ya está respondida en http://dieharddeveloper.blogspot.in/2013/07/c-memory-layout-and-process-image.html aquí hay un extracto de allí: en el medio del espacio de direcciones del proceso, hay es una región está reservada para objetos compartidos. Cuando se crea un nuevo proceso, el administrador de procesos primero asigna los dos segmentos del ejecutable a la memoria. Luego decodifica el encabezado ELF del progtwig. Si el encabezado del progtwig indica que el ejecutable se vinculó con una biblioteca compartida, el administrador de procesos (PM) extraerá el nombre del intérprete dynamic del encabezado del progtwig. El intérprete dynamic apunta a una biblioteca compartida que contiene el código del enlazador en tiempo de ejecución.