3

从我到目前为止所读到的,似乎引用变量根本不应该占用任何内存。相反,它们被视为它们引用的完全相同的变量,但名称不同。

但是,当我运行以下代码时,似乎并非总是如此:

#include <cstdio>
struct A
{
    int m[3];
};
struct B: A
{
    B():x(m[0]), y(m[1]), z(m[2]){}
    int& x;
    int& y;
    int& z;
};
int main(){
    printf("%u, %u\n", sizeof(A), sizeof(B));
    return 0;
}

输出:

12, 40

为什么B比A大那么多?

有没有其他方法可以访问,例如使用 Bx 访问 Bm[0]?

4

3 回答 3

7

从我到目前为止所读到的,似乎引用变量根本不应该占用任何内存。

您应该进一步阅读;)说真的,引用不是魔术。所以在现实世界中,对象必须以某种方式存储有关引用绑定到哪个对象的信息。因此,虽然从概念上讲,引用没有大小,但实际上它非常像指针,通常编译器只使用指针。与指针不同的行为(非空,不可重新分配,无需取消引用)由编译器在编译时强制执行。

所以你看到的基本上是 A 的大小加上 padding 加上三个指针的大小。我猜你在一个sizeof(int)4 和sizeof(void*)8 的 64 位系统上:

 12 bytes for the A subobject (4 for each int)
+ 4 bytes padding (to get to a multiple of 8 bytes)
+24 bytes for the 3 references/pointers in B (8 for each one)
--------------
 40 bytes total

对于您的另一个问题,给定一个b类型的对象B,您可以b.m[0]直接访问它,因为它是公开的A并且是公开继承的。在没有您遇到的引用开销的情况下给它另一个名称是不可能的。

于 2013-04-17T14:07:46.270 回答
4

你解释错了。纯粹在本地使用的引用可以并且经常被优化器消除。请注意,在它的生命周期内,我们仍然需要将它存储在某个地方(比如在寄存器中)。

编译器不能像局部变量那样容易地预测对象的生命周期,因此,成员引用实际上不能被替换和丢弃:有必要保存指向实际内容的指针(4 字节或 8 字节)在对象生命周期内保持成员一致。

于 2013-04-17T14:06:13.480 回答
2

引用就像一个指针,它不能为空,也不能被“重新定位”(指向它最初指向的东西以外的东西)。因此,我们可能期望引用占用与指针相同的空间量(尽管不能保证)。所以三个整数,4 个字节用于对齐,然后三个 8 字节指针将是 40 个字节,使您的示例完全合理。

你可以让一个方法像B.x()返回一个值而不占用更多空间。但是由于 C++ 缺少“属性”,因此您无法B.x返回不占用空间的内容(即,您无法创建看起来像成员变量访问但行为类似于方法调用的内容)。

于 2013-04-17T14:05:20.990 回答