c++ - 其他对象中的对象真的共享同一个地址吗?

标签 c++ object memory

我最近在做项目的时候遇到了这个问题,让我有点困惑。所以我决定写一个测试程序来得到一个确定的答案:

#include <iostream>

using namespace std;

class layer3{
public:
    layer3(){}
    ~layer3(){}     
private:

};


class layer2{
public:
    layer2(){}
    ~layer2(){}

    layer3* GetBAddress(){return &b;}
private:
    layer3 b;
};


class layer1{
public:
    layer1(){}
    ~layer1(){}

    //returns the address of a, which is a 'layer2' object
    layer2* GetaAddress(){return &a;}
    //returns the address of b, which is is a layer 3 object
    layer3* GetDeepBAddress(){return a.GetBAddress();}
private:
    layer2 a;

};

int main(){

    layer1 t;
    cout << &t << "  : layer 1's address" << endl;
    cout << t.GetaAddress() <<  "  : layer 2's address" <<endl;
    cout << t.GetDeepTLAddress() <<  "  : layer 3's address" <<endl;

}

这个程序创建了 3 个对象。 layer2是在layer1里面创建的,layer3是在layer2里面创建的。然后我调用以获取 layer1、layer2 和 layer3 的地址,就像之前发生的那样,这是输出:

$ ./a.exe
0x28ac4f  : layer 1's address
0x28ac4f  : layer 2's address
0x28ac4f  : layer 3's address

所有这三个对象如何共享内存中的同一个位置?如果我将此程序缩放为具有 50 个层(对象)会怎样?还是一万?我不太确定这怎么可能。谁能帮我解释一下这里发生了什么?

编辑:可能是因为我在私有(private)而不是在对象的构造函数中实例化了对象?呸,我不知道。

最佳答案

最明确的答案是 C++ 标准给出的:

Two objects that are not bit-fields may have the same address if one is a subobject of the other, or if at least one is a base class subobject of zero size and they are of different types; otherwise, they shall have distinct addresses.

也就是说,如果一个对象是另一个对象的对象,则它们可能具有相同的地址。

在 C++11 中,standard-layout struct(尽管它的名称,也可以是 class)对象的第一个成员保证具有相同的地址作为对象本身:

A pointer to a standard-layout struct object, suitably converted using a reinterpret_cast, points to its initial member (or if that member is a bit-field, then to the unit in which it resides) and vice versa.

由于您的类都是标准布局,因此您观察到的行为由 C++11 保证。

在 C++03 中,规则类似,但适用于POD-struct 类型,而不是standard-layout struct 类型。但是,您的类不是POD-struct 类型,因为它们具有用户定义的析构函数。因此,C++03 不保证您在此处看到的行为。

那么为什么会发生这种情况呢?好吧,一个类实际上是一种将一些数据组合在一起并提供对该数据的操作的方法。考虑一个只包含 int 的类,如下所示:

class A
{
  int x;
};

所有这个类都是由 int 组成的。当您创建类型为 A 的对象时,您真正要做的就是为其内部分配足够的空间并初始化它们(或者在本例中,不初始化它们)。假设我们创建了 A 的两个实例:

A a1;
A a2;

我们在内存中有什么?你可以想象它看起来像这样:

   a1     a2
┌──────┬──────┐┄┄
│  A   │  A   │
└──────┴──────┘┄┄
Memory ------->

如果我们知道 A 只包含一个 int - 也就是说,一个 A 对象真的仅此而已 比一个 int(除了一些填充)——然后我们知道如果我们把它分解得更多一点,内存实际上看起来像这样:

   a1     a2
┌──────┬──────┐┄┄
│ int  │ int  │
└──────┴──────┘┄┄
Memory ------->

你可以在这里看到 Aint 都有相同的地址,因为 int 是类型对象的子对象A。如果 A 包含 intchar,它可能看起来像这样:

       a1            a2
┌──────┬──────┬──────┬──────┐┄┄
│ int  │ char │ int  │ char │
└──────┴──────┴──────┴──────┘┄┄
Memory ------->

我们知道 char 的地址比 int 高,因为标准再一次这样说:

Nonstatic data members of a (non-union) class with the same access control (Clause 11) are allocated so that later members have higher addresses within a class object.

请注意,子对象不一定与其包含的对象共享其地址,即使它是第一个对象。这完全取决于编译器。

关于c++ - 其他对象中的对象真的共享同一个地址吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14481180/

相关文章:

java - 如何预测java.lang.OutOfMemory异常?

python - 如何分析 Python 中的内存使用情况?

c++ - 使用 CMake 构建模块化 C++ 项目

Javascript 对象数组转换成字符串?

javascript - 如何将有关事件的信息传递给 JavaScript 函数

c++ - 我应该将分配器作为函数参数传递吗? (我对分配器的误解)

c++ - Eigen block 不是左值?

c++ - 如何线程化作为类方法的可调用函数

c++ - 如何使用 C++ opencl api 将参数传递给 ocl 内核?

Javascript 按字母顺序排序并将所有 double 移动到数组的末尾