以下代码可以在g ++和Visual C++下通过编译.为什么合法?它看起来不合理,可能会导致隐藏的错误.
int main() {
int i = i;
}
Run Code Online (Sandbox Code Playgroud)
Luc*_*ore 44
编辑:它在语法上是合法的,但如果你使用,会导致未定义的行为x.
这是不合法的,因为您将未初始化的变量与另一个(好的,相同的)未初始化的变量分配.仅仅因为它编译并不意味着它是合法的.它是有效的C++语法,是的,但不合法.
赋值运算符的右侧必须在赋值时进行全面评估.在这种情况下,那i是没有初始化的.
致Jtop的积分,他挖出了报价:
4.1/1,左值到右值的转换
[...]如果对象未初始化,则需要进行此转换的程序具有未定义的行为.
Ste*_*sop 14
语法允许的原因是,在某些奇怪的情况下,您可能会想到在自己的初始化程序中使用指针或引用的变量:
struct ThingManager {
void *thing;
ThingManager(void *thing) : thing(thing) {}
void Speak() {
if (thing == (void*)this) {
std::cout << "I'm managing myself\n";
} else {
std::cout << "I'm managing " << thing << "\n";
}
}
};
ThingManager self_manager(&self_manager);
ThingManager other_manager(&self_manager);
Run Code Online (Sandbox Code Playgroud)
因此,C++允许您在其自己的初始化表达式中引用对象(其名称在范围内).然后就像在C++中一样,确保你没有实际使用未初始化的值是你的问题(例如,int i = i;确实使用了未初始化的值).
您的编译器可能有助于识别未初始化值的使用,但标准并不要求它.
您可以g++通过-Winit-self(与...一起-Wuninitialized)警告您这个用例,如果您将警告视为错误,它应该满足您的需求.
这种使用复制构造函数进行自初始化的技术有时用于抑制全局对象的默认构造函数/初始化程序的执行.如果全局对象的默认构造函数只是0初始化对象,但在构造函数执行之前使用了对象,则可能需要这样做.作为C的回归,0在程序启动时初始化全局变量,然后C++运行时开始执行全局构造函数.对于那些已经执行的已定义构造函数仅仅0是对象的狭窄情况,自我初始化不会造成任何伤害.
在一般情况下,复制构造函数自初始化是不好的做法,因为它通常会导致使用未初始化的变量导致的相同类型的问题(即,未定义的行为).在OP问题的特定示例中,i是本地的main,因此未初始化.读取未初始化变量的结果始终是未定义的行为.
| 归档时间: |
|
| 查看次数: |
2553 次 |
| 最近记录: |