为什么在ctor中未收到有关访问未初始化成员变量的编译器警告? [英] Why do I not get compiler warning about access uninitialized member variable in ctor?

查看:106
本文介绍了为什么在ctor中未收到有关访问未初始化成员变量的编译器警告?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是一个简单的测试用例,无需任何警告即可编译。看起来像是一个常见错误,但是clang,gcc和Visual Studio在这种情况下不会发出警告。为什么?

Here is a simple test case that compiles without any warning. Looks like a common mistake but clang, gcc and visual studio doesn't emit warning in this case. Why?

class Image {
  private:
    int width, height;
    int* array;
  public:
    Image(int _width, int _height);
    void crashTest();
};
Image::Image(int _width, int _height)
{
  array = new int[width * height];
               // ^^^^^   ^^^^^^ this is wrong
               // I expect a warning here e.g.: 'width is uninitialized here'
  width = _width;
  height = _height;
}
void Image::crashTest()
{
  for (int x = 0; x < width; ++x)
  {
    for (int y = 0; y < height; ++y)
      array[x + y * width] = 0;
  }
}
int main()
{
  const int ARRAY_SIZE = 1000;
  Image image(ARRAY_SIZE, ARRAY_SIZE);
  image.crashTest();
  return 0;
}

例如:

g++ -Wall -Wextra -O2 -Wuninitialized test.cpp
clang++ -Wall -Wextra -O2 -Wuninitialized test.cpp

没有警告我

推荐答案

简短回答



如注释中所指出,从未初始化的变量读取是未定义的行为。编译器没有义务为此提供警告。

Short Answer

As pointed out in the comments, reading from an uninitialized variable is undefined behavior. Compilers are not obligated by the standard to provide a warning for this.

(事实上,只要您的程序表达了未定义的行为,编译器就会从任何和所有义务...)

(In fact, as soon as your program expresses undefined behavior, the compiler is effectively released from any and all obligations...)

来自 [defns.undefined] (标准)(强调):

From section [defns.undefined] of the standard (emphasis added):


未定义的行为

undefined behavior

本国际标准对此没有规定的行为

behavior for which this International Standard imposes no requirements

[注意:当本国际标准省略行为的任何明确定义或程序使用错误的构造或错误的数据时,可能会出现未定义的行为。 允许的不确定行为范围从完全忽略具有无法预测结果的情况 ,到在翻译或程序执行过程中以环境特征记录的方式进行行为(有无发行诊断消息),以终止翻译或执行(伴随诊断消息的发布)。许多错误的程序构造不会引起未定义的行为。他们需要被诊断。 —尾注]

[ Note: Undefined behavior may be expected when this International Standard omits any explicit definition of behavior or when a program uses an erroneous construct or erroneous data. Permissible undefined behavior ranges from ignoring the situation completely with unpredictable results, to behaving during translation or program execution in a documented manner characteristic of the environment (with or without the issuance of a diagnostic message), to terminating a translation or execution (with the issuance of a diagnostic message). Many erroneous program constructs do not engender undefined behavior; they are required to be diagnosed. —end note ]






长答案



编译器很难检测到这种情况(如果确实检测到,则很难以某种有用的方式通知用户)。


Long Answer

This can be a difficult situation for a compiler to detect (and if it does detect it, it's difficult to inform the user about it in some useful way).

您的代码仅表现出未定义的行为,因为它试图读取未初始化的成员变量 宽度高度。它们是成员变量这一事实是使这种情况难以诊断的原因之一。

Your code only exhibits undefined behavior because it's trying to read from uninitialized member variables width and height. The fact that they're member variables is one of the things that can make this situation tricky to diagnose.

有了局部变量,检测这种情况的静态分析就可以

With local variables, the static analysis involved in detecting this can be relatively straightforward (not all the time, mind you).

例如,很容易在这里看到问题:

For example, it's very easy to see the problem here:

    int foo()
    {
        int a;
        int b = 0;

        return a + b; // Danger! `a` hasn't been initialized!
    }

在这种情况下如何:

    int foo(int& a)
    {
        int b = 1;

        return a + b; // Hmm... I sure hope whoever gave me `a` remembered to initialize it first 
    }

    void bar()
    {
        int value;
        int result = foo(value); // Hmm... not sure if it matters that value hasn't been initialized yet
    }

一旦我们开始处理范围超出单个块的变量,就很难检测变量是否已初始化。

As soon as we start dealing with variables whose scope extends beyond a single block, it's very difficult to detect whether or not a variable has been initialized.

现在,将此与手头的问题联系起来(您的问题):变量 width height 不在构造函数中-它们可能已在构造函数外部初始化

Now, relating this back to the problem at hand (your question): the variables width and height are not local to the constructor - they could have been initialized outside the constructor.

例如:

    Image::Image(int _width, int _height)
    {
      Initialize();

      array = new int[width * height]; // Maybe these were initialized in `Initialize`...

      width = _width;
      height = _height;
    }

    Image::Initialize()
    {
        width = 0;
        height = 0;
    }

在这种情况下,编译器是否应发出警告?

Should the compiler emit a warning in this scenario?

经过一些粗略的分析,我们可以说不,它不应该警告,因为我们可以看到 Initialize 方法确实可以初始化有问题的成员变量。

After some cursory analysis we can conclusively say "no, it shouldn't warn", because we can see that the Initialize method does indeed initialize the member variables in question.

但是如果 Initialize 将其委托给另一个方法会怎样? MoreInitialize()?然后该方法将其委托给另一个方法 YetEvenMoreInitialize 这开始看起来像是一个问题,我们无法合理地认为希望编译器解决。

But what if Initialize delegates this to another method MoreInitialize()? And that method delegates it to another method YetEvenMoreInitialize? This begins to look like a problem that we can't reasonably expect the compiler to solve.

这篇关于为什么在ctor中未收到有关访问未初始化成员变量的编译器警告?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆