g ++ -Wreorder有什么意义?

时间:2009-12-01 18:38:27

标签: c++ g++ compiler-warnings

g ++ -Wall选项包括-Wreorder。该选项的作用如下所述。我不明白为什么有人会关心(特别是在-Wall中默认打开它)。

-Wreorder (C++ only)
  Warn when the order of member initializers given in the code does not
  match the order in which they must be executed.  For instance:

    struct A {
      int i;
      int j;
      A(): j (0), i (1) { }
    };

  The compiler will rearrange the member initializers for i and j to
  match the declaration order of the members, emit-ting a warning to that
  effect.  This warning is enabled by -Wall.

5 个答案:

答案 0 :(得分:227)

考虑:

struct A {
    int i;
    int j;
    A() : j(0), i(j) { }
};

现在i被初始化为某个未知值,而不是零。

或者,i的初始化可能会产生一些副作用,顺序很重要。 E.g。

A(int n) : j(n++), i(n++) { }

答案 1 :(得分:35)

问题是有人可能会在构造函数中看到成员初始化者的列表,并认为它们是按照该顺序执行的(先是j,然后是i)。它们不是,它们按照成员在班级中定义的顺序执行。

假设你写了A(): j(0), i(j) {}。有人可能会读到这一点,并认为我最终得到的值为0.它没有,因为你用j初始化它,它包含垃圾,因为它本身没有被初始化。

警告提醒你写A(): i(j), j(0) {},希望看起来更可疑。

答案 2 :(得分:14)

其他答案提供了一些很好的例子来证明警告选项的合理性。我以为我会提供一些历史背景。 C ++的创建者Bjarne Stroustrup在他的书The C++ programming language(第3版,第259页)中解释道:

  

在执行包含类的自身构造函数的主体之前调用成员的构造函数。构造函数按它们在类中声明的顺序调用,而不是它们在初始化列表中出现的顺序。为避免混淆,最好按声明顺序指定初始值设定项。成员析构函数以相反的构造顺序调用。

答案 3 :(得分:9)

如果你的初始化者有副作用,这可能会咬你。考虑:

int foo() {
    puts("foo");
    return 1;
}

int bar() {
    puts("bar");
    return 2;
}

struct baz {
    int x, y;
    baz() : y(foo()), x(bar()) {}
};

上面会打印“bar”然后打印“foo”,即使直觉上会假设订单是在初始化列表中写的。

或者,如果xy是一些带有构造函数的用户定义类型,那么该构造函数也可能有副作用,但结果不明显。

当一个成员的初始化程序引用另一个成员时,它也可以表现出来。

答案 4 :(得分:6)

警告存在是因为如果您只是阅读构造函数,则j之前的i似乎已初始化。如果用于初始化另一个,则会成为问题,如

struct A {
  int i;
  int j;
  A(): j (0), i (this->j) { }
};

当您查看构造函数时,此看起来是安全的。但实际上,j尚未在用于初始化i的位置进行初始化,因此代码将无法按预期工作。因此警告。