我期望会发生的是,因为参考类型和我不匹配我必须已经转换为临时然后分配给r2但是当我改变时我明确地改为53 r2也改变了
int i = 42;
const int &r2 = i;
i = 53;
std::cout << r2<<"\n";
return 0;
使用双
时不会发生同样的情况double i = 42.4;
const int &r2 = i;
i = 53.7;
std::cout << r2<<"\n";
return 0;
此处打印的值与预期值相同42
答案 0 :(得分:3)
语言规则明确声明如果引用的类型与lvalue初始化程序的类型引用兼容,则引用将直接绑定到初始化程序。见8.6.3 / 5
5 类型“cv1 T1”的引用由“cv2 T2”类型的表达式初始化,如下所示:
- 如果引用是左值引用和初始化表达式
- 是左值(但不是位域),“cv1 T1”与“cv2 T2”引用兼容,
[...]
然后引用绑定到初始化表达式lvalue。
参考兼容性允许参考类型中的额外cv资格。因此,尽管您的引用类型中有额外的const
,但语言仍然需要将其直接绑定到i
。换句话说,在您的第一个示例中,实际执行匹配的类型。
在您的第二个示例中,类型非常不同,彼此不是参考兼容的。没有直接绑定引用。
答案 1 :(得分:1)
您手上有两种不同的情况。这里
int i = 42;
const int &r2 = i;
你有一个对象。和一个相同类型的const引用。 r2
可能会直接与i
绑定。您不能使用r2
修改i
,但i
本身不是常量。您基本上创建了对象的const视图。
这是设计的,当你想到它时,非常有用。假设我们要打印一百万个std::vector
个对象。我们的函数应该传递一个引用,最好不要修改向量。所以通过&#34; const view&#34;矢量正是我们所需要的。
在另一种情况下,您有一种类型的对象,以及对完全不相关类型的引用。引用不能直接绑定,所以我们确实为它创建了一个临时的int
来绑定。临时和原始对象是分开的。正如你所观察到的那样。
答案 2 :(得分:0)
在双重的情况下,你绑定一个const int引用,所以在这种情况下需要临时(转换),在第一种情况下,你说这个值不能通过引用更改但没有任何阻止原来被改变了。
考虑像const volatile int&amp; amp;我= ...;在那里你明确地告诉编译器我可能因为编译器无法推断而改变。
答案 3 :(得分:0)
在分配给不同类型的引用之前,会发生类型转换,并且值将存储在不同的位置,引用将指向该位置。如果它的类型不同,r2将不会指向i。在你的情况下,cvttsd2si
将被调用,double值将被转换为有符号的双字整数。
检查为下面的代码版本生成的汇编代码。
对于不同类型
#double i = 42 ;
movsd .LC0(%rip), %xmm0 #, tmp90
movsd %xmm0, -8(%rbp) # tmp90, i
# *.cpp:6: const int &r2 = i;
movsd -8(%rbp), %xmm0 # i, tmp91
cvttsd2si %xmm0, %eax # tmp91, _2
movl %eax, -20(%rbp) # _2, D.39824
leaq -20(%rbp), %rax #, tmp92
movq %rax, -16(%rbp) # tmp92, r2
当变量和引用是相同类型时。
# *.cpp:5: int i = 42;
movl $42, -12(%rbp) #, i
# *.cpp:6: const int &r2 = i;
leaq -12(%rbp), %rax #, tmp89
movq %rax, -8(%rbp) # tmp89, r2