我有以下代码
#include <iostream>
void foo(const int* const &i_p) {
std::cout << &i_p << std::endl;
}
int main () {
int i = 10;
int* i_p = &i;
std::cout << &i_p << std::endl;
foo(i_p);
}
打开
x86-64 clang 9.0.0
,输出为
Program returned: 0
0x7ffc43de63f8
0x7ffc43de6400
在
x86-64 clang 10.0.0
编译器资源管理器链接时,输出变为
Program returned: 0
0x7ffc9da01ef0
0x7ffc9da01ef0
这里进行了什么优化来提供相同的地址?我相信应该实现一个临时对象,因为我们无法将低级
const
指针绑定到低级 non-const
。
您只有一个
i_p
指针,自然地,&i_p
中的 main
和 &i_p
中的 foo
应该产生相同的地址。
const int * const
与 int *
是引用兼容,因为指向
int*
的指针,即 int**
可以通过 限定转换转换为
const int * const*
。
因此,对 const int * const
的引用可以绑定到 int*
。
没有什么需要创建第二个对象,至少在当前草案中不需要。然而,过去并不总是这样,并且在引用绑定期间并不总是考虑资格转换。
CWG2018。限定转换 vs 引用绑定 指出不考虑限定转换并创建临时对象,如本例所示:
const int &&x1 = make<int&&>(); // ok, binds directly
const int *const &&x2 = make<int*&&>(); // weird, binds to a temporary
const int *&&x3 = make<int*&&>(); // weird, binds to a temporary
这个例子与你的类似。 如果
const int* const &i_p
不是简单地绑定到 i_p
中的 main
而是在调用 foo
时创建一个全新的临时指针,那么它将是一个单独的对象。请注意,由于临时物化,const&
可以绑定到临时对象。
这种行为是一个缺陷,而且看起来并不是故意的。 这个缺陷似乎已在 GCC 7 和 clang 10 中得到解决,这就是为什么您不再看到创建两个单独的指针。