为什么'int i = i;' 法律?

Aer*_*key 27 c++

可能重复:
int var = 1; void main(){int i = i; }

以下代码可以在g ++和Visual C++下通过编译.为什么合法?它看起来不合理,可能会导致隐藏的错误.

int main() {
  int i = i;
}
Run Code Online (Sandbox Code Playgroud)

Luc*_*ore 44

编辑:它在语法上是合法的,但如果你使用,会导致未定义的行为x.

这是合法的,因为您将未初始化的变量与另一个(好的,相同的)未初始化的变量分配.仅仅因为它编译并不意味着它是合法的.它是有效的C++语法,是的,但不合法.

赋值运算符的右侧必须在赋值时进行全面评估.在这种情况下,那i是没有初始化的.

致Jtop的积分,他挖出了报价:

4.1/1,左值到右值的转换

[...]如果对象未初始化,则需要进行此转换的程序具有未定义的行为.

  • 如果它有帮助:4.1/1,左值到右值转换,"如果对象未初始化,则需要此转换的程序具有未定义的行为".你不能读取未初始化的对象,所以除非你在自己的初始值设定项中读取它并且认为"i"没有未初始化,否则我认为标准对此案例的描述并不存在大量的争论. (9认同)
  • @nhahtdh在标准中定义的意义上,还有什么?**它是否编译与合法性无关.**否则我们没有未定义的行为.**如果你没有线索,停止(下)投票,人!** (8认同)
  • 我认为你必须通过_valid_和_legal_来区分你的意思.许多人似乎混淆了这两个词. (7认同)
  • 这是100%正确---代码是非法的.如果他提到关键词"未定义的行为",答案可能稍好一点,但他涵盖了所有重要的观点:有效的语法,但不合法; 在初始化之前评估`i`; 等等 (3认同)
  • @LuchianGrigore:法律在什么意义上?我认为这样做是完全错误的.但是编译器很乐意编译它. (2认同)

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;确实使用了未初始化的值).

您的编译器可能有助于识别未初始化值的使用,但标准并不要求它.


jxh*_*jxh 7

您可以g++通过-Winit-self(与...一起-Wuninitialized)警告您这个用例,如果您将警告视为错误,它应该满足您的需求.

这种使用复制构造函数进行自初始化的技术有时用于抑制全局对象的默认构造函数/初始化程序的执行.如果全局对象的默认构造函数只是0初始化对象,但在构造函数执行之前使用了对象,则可能需要这样做.作为C的回归,0在程序启动时初始化全局变量,然后C++运行时开始执行全局构造函数.对于那些已经执行的已定义构造函数仅仅0是对象的狭窄情况,自我初始化不会造成任何伤害.

在一般情况下,复制构造函数自初始化是不好的做法,因为它通常会导致使用未初始化的变量导致的相同类型的问题(即,未定义的行为).在OP问题的特定示例中,i是本地的main,因此未初始化.读取未初始化变量的结果始终是未定义的行为.