C++构造函数:初始化常量引用时出现垃圾
C++ constructor: garbage while initialization of const reference
这个代码出了什么问题,为什么我得到了错误的答案:
class X
{
private:
const int a;
const int& b;
public:
X(): a(10) , b(20)
{
// std::cout << "constructor : a " << a << std::endl;
// std::cout << "constructor : b " << b << std::endl;
}
void display()
{
std::cout << "display():a:" << a << std::endl;
std::cout << "display():b:" << b << std::endl;
}
};
int
main(void)
{
X x;
x.display();
return 0;
}
上面的代码会给我的结果
display():a:10
display():b:1104441332
但是,如果我删除默认构造函数中注释的2行,它会给我正确的结果,即
constructor : a 10
constructor : b 20
display():a:10
display():b:20
请帮忙,谢谢
您正在初始化b
作为对临时的引用。
值20
是创建的,并且仅存在于构造函数的作用域中。
之后代码的行为非常有趣——在我的机器上,我得到的值与您发布的值不同,但基本行为仍然是不确定的。
这是因为当引用所指向的值超出范围时,它开始引用垃圾内存,从而产生不可预测的行为。
参见常量引用是否延长了临时引用的寿命?;答案https://stackoverflow.com/a/2784304/383402链接到C++标准的相关部分,特别是以下文本:
A temporary bound to a reference member in a constructor’s ctor-initializer
(12.6.2) persists until the constructor exits.
这就是为什么您总是在构造函数中的打印中获得正确的值,之后很少(但有时可能!)。当构造函数退出时,引用挂起并且所有赌注都关闭。
我会让我的编译器回答这个问题:
$ g++ -std=c++98 -Wall -Wextra -pedantic test.cpp
test.cpp: In constructor 'X::X()':
test.cpp:9:26: warning: a temporary bound to 'X::b' only persists until the constructor exits [-Wextra]
$
您也应该打开编译器上的警告。
b
是指临时的。由于临时20
在技术上已超出范围,因此在读取时,您读取的(打印时)位置无效。
解释不一致的结果:
这是未定义的行为。如果你:,你看到的可能会有所不同
- 更改编译器
- 更改编译器设置
- 为另一个体系结构构建
- 更改班级成员布局
- 在
x
实例附近的内存区域中添加或删除内容 - 等等
您应该始终避免未定义的行为。
但为什么值会改变您的引用可能是指在打印时已被重写(例如重复使用)的堆栈地址。
您将const&
绑定到一个临时的,它不会超出对构造函数的调用。C++03标准特别指出,"构造函数的ctor初始值设定项(12.6.2)中与引用成员的临时绑定将持续到构造函数退出为止"(12.2/5"临时对象")。
所以你的代码有未定义的行为——你可能会得到一些胡言乱语,或者看起来"有效"的东西。
FWIW,MSVC 2010对该代码发出以下警告:
C:temptest.cpp(12) : warning C4413: 'X::b' : reference member is initialized to a temporary that doesn't persist after the constructor exits
- 在类构造函数中传递对外部函数的引用
- 在 c++ 中将变量作为结构构造函数中的引用传递
- C++ 尝试在不存在的构造函数中引用已删除的函数(使用 rapidJson)
- 移动构造函数和右值引用
- 为什么我的运算符 + 重载尽管是通过引用传递的,但仍调用我的复制构造函数?
- 如何使用 swig 修改类构造函数以保留对其中一个构造函数参数的引用?
- 在引用初始化中使用已删除的复制构造函数进行复制初始化
- C++:右值引用构造函数和复制省略
- 当有右值构造函数可用时,为什么从右值调用类引用构造函数重载?
- 引用构造函数时链接失败
- 为什么调用转发引用构造函数而不是复制构造函数?
- 为什么使用已删除的右值引用构造函数?
- 对 std::Optional 的转发引用构造函数的约束
- 模板是否应该为不同类型的参数制作非 Rvalue 引用构造函数/赋值
- 我是否应该对非引用构造函数参数手动调用move
- 使用左值引用错误地调用了Rvalue引用构造函数
- C++未定义的引用构造函数错误
- 调用左值引用构造函数而不是右值引用构造函数
- C++引用构造函数语法
- 不能引用构造函数的地址