C++中"Class instantiated object and variable inside the object address"的内存地址
Memory address of "Class instantiated object and variable inside the object address" in C++
我正在努力理解主程序中声明的变量与实例化 class 对象中的变量之间内存寻址差异的概念!
我的问题是,当我在主程序中声明两个变量时,例如 "int a, int b",它需要 4+4 个字节,并且在内存中的某个位置有一个特定的两个地址。示例 "a is in the memory 0x248444 and b is in 0x248448"...在这种情况下很好....
当class实例化对象有两个变量"int c, int d"时,对象占用一个8字节的内存地址,例如“0x248544”,那么"int c and int d"的地址呢?
所以 int c 和 int d 的地址在对象地址“0x248544”内?
int c 和 int d 有特定地址吗?
如何理解/实例化的class对象地址和该对象内部变量的地址有什么区别?
希望我的问题很清楚....
在网上搜索后,我找到了一本名为"inside the C++ object model"的书,但对于在实例化class对象中声明的变量和在main中声明的变量的内存差异有基本的了解。有人请帮我说清楚。
提前致谢。
您可以将 class 实例视为其成员变量的包络。 class 实例的大小是其成员变量的大小加上它们之间的可选填充的总和。通常(继承和多态性会弄乱这一点)第一个成员变量的地址与 class 实例的地址相同。您可以获取成员的地址并在调试器中调查它们以查看它是如何工作的。例如
class C
{
public:
int a = 1;
int b = 2;
};
C c;
int* p_a = &c.a;
int* p_b = &c.b;
检查c
占用的内存,你会看到里面有值1
和2
。
成员变量的顺序被保留,并且由于填充会影响 class 实例的大小。
空 class 的实例必须有一个地址,因此它的大小永远不会为 0。
成员函数是另一回事。虽然它们也在内存中的某个位置,但它们由所有实例共享,因此存储在一个单独的位置,与实例分开。
好的,你有一个像这样的 class C:
class C
{
int c;
int d;
};
class C (C c
) 的一个实例会占用一些内存,它需要(假设 int 是 4 个字节大——虽然这不一定在所有机器上都是这样)8 个字节.
如果一个实例位于地址0x248544,它将恰好占据该地址+下一个后续字节的字节。在上面这样一个简单的 class 中,没有任何进一步的条件,c 将占据这八个字节的前四个,d 将占据接下来的四个。
因此 c.c
与您的对象 c
具有完全相同的地址,并且 c.d
位于四个字节之后,因此地址为 0x248548。
但是请注意,第一个成员不一定与您的对象具有相同的地址!让我们修改我们的 class C:
class C
{
virtual ~C() { } // virtual destructor -> C gets virtual!
int c;
int d;
};
现在,sizeof(C) 将为 16(!)(前提是指针需要 8 字节存储空间,就像在现代 64 位硬件上一样)。为什么? class 获得一个指向 vtable 的附加指针,它通常是 class C 的第一个(但不可见)成员。
因此 c
仍将位于地址 0x248544,但现在指向 vtable 的(不可见)指针共享该地址; c.c
在后面,因此位于地址0x2484c,c.d
则位于0x24850。
在这方面,C++ 不同于 C,其中结构的第一个成员总是共享结构本身的地址...
尽管在 C 和 C++ 中,两个后续成员不一定必须 "touch" 彼此,它们之间可能会填充一些字节 - 关键字字节对齐。
此外,C++ 允许对 class 的成员重新排序:
而在 C 中,如果结构成员 a
在 b
之前声明,那么 a
在内存中也必须放在 b
之前,这在 C++ 中仅需要相同辅助功能的成员!
class C
{
int a;
public:
int b;
private:
int c;
};
编译器现在允许按原样保留顺序,但它也可以将 b
放在其他两个之前或之后 - 只有 a
不允许放在 c
.
长话短说:所有这些内存布局的东西比您可能预期的要复杂得多...
vtables 旁注:vtable 指针不需要存在(相对于 C++ 标准)——如果任何编译器供应商找到更好的解决方案来实现多态性,他们可以自由地这样做——if 他们发现...但是 vtables 是当前最先进的技术,一种事实上的标准。
我正在努力理解主程序中声明的变量与实例化 class 对象中的变量之间内存寻址差异的概念!
我的问题是,当我在主程序中声明两个变量时,例如 "int a, int b",它需要 4+4 个字节,并且在内存中的某个位置有一个特定的两个地址。示例 "a is in the memory 0x248444 and b is in 0x248448"...在这种情况下很好....
当class实例化对象有两个变量"int c, int d"时,对象占用一个8字节的内存地址,例如“0x248544”,那么"int c and int d"的地址呢?
所以 int c 和 int d 的地址在对象地址“0x248544”内? int c 和 int d 有特定地址吗?
如何理解/实例化的class对象地址和该对象内部变量的地址有什么区别?
希望我的问题很清楚....
在网上搜索后,我找到了一本名为"inside the C++ object model"的书,但对于在实例化class对象中声明的变量和在main中声明的变量的内存差异有基本的了解。有人请帮我说清楚。
提前致谢。
您可以将 class 实例视为其成员变量的包络。 class 实例的大小是其成员变量的大小加上它们之间的可选填充的总和。通常(继承和多态性会弄乱这一点)第一个成员变量的地址与 class 实例的地址相同。您可以获取成员的地址并在调试器中调查它们以查看它是如何工作的。例如
class C
{
public:
int a = 1;
int b = 2;
};
C c;
int* p_a = &c.a;
int* p_b = &c.b;
检查c
占用的内存,你会看到里面有值1
和2
。
成员变量的顺序被保留,并且由于填充会影响 class 实例的大小。
空 class 的实例必须有一个地址,因此它的大小永远不会为 0。
成员函数是另一回事。虽然它们也在内存中的某个位置,但它们由所有实例共享,因此存储在一个单独的位置,与实例分开。
好的,你有一个像这样的 class C:
class C
{
int c;
int d;
};
class C (C c
) 的一个实例会占用一些内存,它需要(假设 int 是 4 个字节大——虽然这不一定在所有机器上都是这样)8 个字节.
如果一个实例位于地址0x248544,它将恰好占据该地址+下一个后续字节的字节。在上面这样一个简单的 class 中,没有任何进一步的条件,c 将占据这八个字节的前四个,d 将占据接下来的四个。
因此 c.c
与您的对象 c
具有完全相同的地址,并且 c.d
位于四个字节之后,因此地址为 0x248548。
但是请注意,第一个成员不一定与您的对象具有相同的地址!让我们修改我们的 class C:
class C
{
virtual ~C() { } // virtual destructor -> C gets virtual!
int c;
int d;
};
现在,sizeof(C) 将为 16(!)(前提是指针需要 8 字节存储空间,就像在现代 64 位硬件上一样)。为什么? class 获得一个指向 vtable 的附加指针,它通常是 class C 的第一个(但不可见)成员。
因此 c
仍将位于地址 0x248544,但现在指向 vtable 的(不可见)指针共享该地址; c.c
在后面,因此位于地址0x2484c,c.d
则位于0x24850。
在这方面,C++ 不同于 C,其中结构的第一个成员总是共享结构本身的地址...
尽管在 C 和 C++ 中,两个后续成员不一定必须 "touch" 彼此,它们之间可能会填充一些字节 - 关键字字节对齐。
此外,C++ 允许对 class 的成员重新排序:
而在 C 中,如果结构成员 a
在 b
之前声明,那么 a
在内存中也必须放在 b
之前,这在 C++ 中仅需要相同辅助功能的成员!
class C
{
int a;
public:
int b;
private:
int c;
};
编译器现在允许按原样保留顺序,但它也可以将 b
放在其他两个之前或之后 - 只有 a
不允许放在 c
.
长话短说:所有这些内存布局的东西比您可能预期的要复杂得多...
vtables 旁注:vtable 指针不需要存在(相对于 C++ 标准)——如果任何编译器供应商找到更好的解决方案来实现多态性,他们可以自由地这样做——if 他们发现...但是 vtables 是当前最先进的技术,一种事实上的标准。