我到处都读到引用不是对象,它们只是别名而且它们在内存中没有位置
int x = 256;
int& rx = x;
std::cout << x << " " << &x << std::endl; // Output: 256 0x15FAB0
std::cout << rx << " " << &rx << std::endl; // Output: 256 0x15FAB0
// seems legit ... fair enough ...
现在考虑以下
const int& r1 = 8; // lvalue ref to const int
int&& r2 = 32; // rvlaue ref to int
const int&& r3 = 128; // rvalue ref to const int
std::cout << r1 << " " << &r1 << std::endl; // Output: 8 0x15FA8C
std::cout << r2 << " " << &r2 << std::endl; // Output: 32 0x15FA74
std::cout << r3 << " " << &r3 << std::endl; // Output: 128 0x15FA5C
// and ...
std::cout << sizeof(r1) << std::endl; // Ouput: 4
std::cout << sizeof(r2) << std::endl; // Ouput: 4
std::cout << sizeof(r3) << std::endl; // Ouput: 4
那么为什么这些引用的行为类似于对象,它们确实具有值,内存地址和大小......它们是否与引用规则不同? 他们是在堆栈上还是在其他地方?
答案 0 :(得分:6)
我猜你真正的问题是“当rvalue / const引用没有引用具有名称的任何东西时,它会在哪里发生?”
const int& r1 = 8; // lvalue ref to const int
int&& r2 = 32; // rvlaue ref to int
const int&& r3 = 128; // rvalue ref to const int
在上述所有三种情况下,编译器在临时位置分配空间,将值放在那里,并为您提供该值的引用。允许编译器执行此操作,因为它可以保证临时位置保持只读。
这就是你的引用获取地址的方式 - 对象(8,32,128)仍然存在,因为编译器会为你创建它们。这些隐藏对象的地址成为引用的地址;这些隐藏对象的大小由sizeof
运算符报告。
答案 1 :(得分:3)
引用的sizeof()
不会为您提供引用本身的大小,而是引用引用所引用的sizeof()
。
struct foo {
int a[128];
};
foo bar;
foo &baz=bar;
std::cout << sizeof(baz) << std::endl;
你在这里得到一个相当大的sizeof()
。显然,这不是引用的大小,而是引用的对象的大小。
这适用于左值和左值参考。
答案 2 :(得分:2)
引用具有地址和大小,因为它绑定到临时。因此,临时的生命周期将延长以匹配参考的生命周期。
§12.2第4,5段明确涵盖了这一点:
4有两种情况,临时表演在不同于完整表达结束时被摧毁。 第一个上下文是调用默认构造函数来初始化数组的元素。如果 构造函数有一个或多个默认参数,破坏默认情况下创建的每个临时值 在构造下一个数组元素之前,参数是按顺序排序的。
5 第二个上下文是指引用绑定到临时 .117引用的临时值 绑定或临时是绑定引用的子对象的完整对象仍然存在 参考的生命周期除外:...
答案 3 :(得分:1)
引用本质上是相同值的另一个名称。正如您在测试中看到的那样,它们具有与原始值相同的大小和地址。如果您创建一个值并直接引用它,那么引用也将是该值的名称。
答案 4 :(得分:1)
int x = 256; int& rx = x;
[...]
const int& r1 = 8; // lvalue ref to const int int&& r2 = 32; // rvlaue ref to int const int&& r3 = 128; // rvalue ref to const int
这两个例子之间没有太大区别。在第一个示例中,您将一个引用(rx
)声明为之前已命名的对象(x
)。在第二个示例中,您的三个引用(r1
,r2
,r3
)引用了在每个引用初始化期间创建的临时对象。
那么为什么这些引用表现得像对象一样,它们确实有值, 内存地址和大小...
他们没有。只是这里的对象只是由引用命名而不是其他任何东西。您的sizeof
和地址运算符仍然适用于这些对象。