内存布局C++;物体 我基本上想知道C++如何在内存中绘制对象。所以,我听说动态强制转换只是用偏移量调整对象在内存中的指针;重新解释允许我们用这个指针做任何事情。我真的不明白。详情将不胜感激 答案是“很复杂”。动态强制转换不只是用偏移量调整指针;它实际上可能检索对象内部的指针以完成其工作。GCC遵循为安腾设计的ABI,但实现范围更广。您可以在这里找到血淋淋的细节:。

内存布局C++;物体 我基本上想知道C++如何在内存中绘制对象。所以,我听说动态强制转换只是用偏移量调整对象在内存中的指针;重新解释允许我们用这个指针做任何事情。我真的不明白。详情将不胜感激 答案是“很复杂”。动态强制转换不只是用偏移量调整指针;它实际上可能检索对象内部的指针以完成其工作。GCC遵循为安腾设计的ABI,但实现范围更广。您可以在这里找到血淋淋的细节:。,c++,memory,object,C++,Memory,Object,每个类都按照声明的顺序排列其数据成员。 允许编译器在成员之间放置填充以提高访问效率(但不允许重新排序) dynamic\u cast的工作原理是一个编译器实现细节,而不是由标准定义的。这一切都取决于编译器使用的ABI reinterpret\u cast只需更改对象的类型即可工作。唯一可以保证有效的是,将指针转换为void*并返回到相同的类指针,将得到相同的指针。如前所述,完整的细节非常复杂,阅读起来很痛苦,并且只对编译器开发人员有用,并且在编译器之间有所不同。基本上,每个对象包含以下内容(通常

每个类都按照声明的顺序排列其数据成员。
允许编译器在成员之间放置填充以提高访问效率(但不允许重新排序)

dynamic\u cast
的工作原理是一个编译器实现细节,而不是由标准定义的。这一切都取决于编译器使用的ABI


reinterpret\u cast
只需更改对象的类型即可工作。唯一可以保证有效的是,将指针转换为void*并返回到相同的类指针,将得到相同的指针。

如前所述,完整的细节非常复杂,阅读起来很痛苦,并且只对编译器开发人员有用,并且在编译器之间有所不同。基本上,每个对象包含以下内容(通常按此顺序排列):

  • 运行时类型信息
  • 非虚拟基本对象及其数据(可能按声明顺序排列)
  • 成员变量
  • 虚拟基本对象及其数据(可能以某些DFS树搜索顺序)
  • 这些数据段可以填充,也可以不填充,以便于内存对齐等。隐藏在运行时类型信息中的是有关类型的内容,虚拟父类的v表等,所有这些都是特定于编译器的


    当涉及到转换时,ReRealtTyStudio只需更改指针的C++数据类型,不做其他任何事情,所以最好确保你知道在使用时你在做什么,否则你会把事情搞得一团糟。code>dynamic_cast与static_cast(在改变指针方面)的功能非常相似,只是它使用运行时类型信息来确定是否可以转换为给定类型,以及如何转换。同样,所有这些都是特定于编译器的。请注意,您不能

    dynamic\u cast
    a
    void*
    ,因为它需要知道在哪里可以找到运行时类型信息,这样它就可以进行所有出色的运行时检查。

    这个问题已经在 以下是其中的摘录:
    在进程的地址空间的中间,有一个区域被保留为共享对象。创建新进程时,进程管理器首先将可执行文件中的两个段映射到内存中。然后解码程序的ELF头。如果程序头指示可执行文件链接到共享库,则process manager(PM)将从程序头中提取动态解释器的名称。动态解释器指向包含运行时链接器代码的共享库

    内存布局主要由实现完成。关键的例外是,给定访问说明符的成员变量将按声明顺序排列

    §9.2.14

    具有相同访问权限的(非联合)类的非静态数据成员 控制权(第11条)的分配是为了使后来的成员拥有更高的控制权 类对象中的地址。非静态资源的分配顺序 未指定具有不同访问控制的数据成员(11)。 实现一致性要求可能会导致两个相邻的成员 不在彼此之后立即分配;也可能 管理虚拟功能的空间要求(10.3)和 虚拟基类(10.1)

    除成员变量外,类或结构需要为成员变量、基类的子对象、虚拟函数管理(如虚拟表)以及这些数据的填充和对齐提供空间。这取决于实现,但安腾ABI规范是一种流行的选择。gcc和clang都遵守它(至少在一定程度上)

    P. Itabi ABI当然不是C++标准的一部分,不具有约束力。要获得更详细的信息,您需要查阅实施者的文档和工具。clang提供了一个查看类的内存布局的工具。例如,以下内容:

    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<typename T>
        // 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);
    }
    
    类的布局

    *** 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]
    
    更多关于这个叮当作响的功能可以在Eli Bendersky的博客上找到:

    gcc提供了一个类似的工具,`-fdump类层次结构'。对于上面给出的类,它打印(除其他外):

    它没有逐项列出成员变量(或者至少我不知道如何使用它),但是您可以知道它们必须在偏移量28和64之间,就像在clang布局中一样

    您可以看到一个基类被单独指定为
    primary
    。当作为
    SBase1
    访问
    Class
    时,这样就不需要调整
    指针

    gcc的等效值为:

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

    Visual C++的等价性是:

    cl main.cpp /c /d1reportSingleClassLayoutTest_A
    

    请参阅:

    您的第一点并不完全正确。您唯一能保证的是,同一访问块中的成员将具有已定义的顺序。如果你想把这一点发挥到极致,你可以说,即使访问权限相同,订单也不再有保证。@Richard。我不确定我是否理解你。编译器不允许对元素重新排序(这是为了与C向后兼容)。什么是访问块。您能告诉我您从标准中获取信息的正确部分吗?访问块(实际上是访问说明符)是类中的
    公共:
    私有:
    、和
    受保护:
    。我发现这篇文章:非常有用,这就是我想要的
    $ g++ -fdump-class-hierarchy -c layout.cpp
    
    cl main.cpp /c /d1reportSingleClassLayoutTest_A