为什么"int i = i;"是合法的?

Why is 'int i = i;' legal?

本文关键字:int 为什么      更新时间:2023-10-16

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

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

int main() {
  int i = i;
}

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

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

分配

运算符的右侧必须在分配时进行全面评估。在这种情况下,这是 i ,它没有初始化。

感谢史蒂夫·杰索普(Steve Jessop),他挖出了这句话:

4.1/1,左值到右值转换

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

语法允许它的原因是,在某些奇怪的情况下,您可能希望通过指针或引用在其自己的初始值设定项中使用变量:

struct ThingManager {
    void *thing;
    ThingManager(void *thing) : thing(thing) {}
    void Speak() {
        if (thing == (void*)this) {
            std::cout << "I'm managing myselfn";
        } else {
            std::cout << "I'm managing " << thing << "n";
        }
    }
};
ThingManager self_manager(&self_manager);
ThingManager other_manager(&self_manager);

因此,C++允许您在其自己的初始值设定项表达式中引用对象(其名称在范围内)。然后,与C++中一样,确保您的实际上没有使用未初始化的值(您的示例,int i = i;确实使用未初始化的值)是您的问题。

编译器可能有助于识别未初始化值的用法,但标准不需要这样做。

你可以让g++-Winit-self(结合-Wuninitialized)警告你这个用例,如果你把警告当作错误,它应该满足你的痒。

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

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

您可以使用任何先前声明的变量作为另一个变量的初始化器。

在这种情况下,编译器一旦解析int i就会将其添加到符号表中,因此当它看到= i初始化器时,可以从前面的声明中解析符号。

这不是一个错误,因为编译器可以理解它,因为它可以生成代码,这些代码明确地完全按照源代码指定的方式执行,即使它在语义上是可疑的。 C 和 C++ 的哲学是编译任何可能以语法方式编译的东西。 语义错误通常只发出警告,并且只有在启用此类警告时才发出警告。

相关文章: