g ++ -Wreorder有什么意义?

Pee*_*oot 140 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.

int*_*nt3 238

考虑:

struct A {
    int i;
    int j;
    A() : j(0), i(j) { }
};
Run Code Online (Sandbox Code Playgroud)

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

或者,初始化i可能具有一些副作用,顺序很重要.例如

A(int n) : j(n++), i(n++) { }
Run Code Online (Sandbox Code Playgroud)

  • 这应该是文档中的示例. (76认同)
  • @Mike这是因为你的编译器(gcc)将未初始化的变量初始化为0,但这不是你应该依赖的东西; 我为0只是未初始化变量的未知值的副作用是0. (5认同)
  • 谢谢.由于我们的大多数类型都是具有简单初始化器的POD类型,因此我没有想到.您的示例比g ++手动示例好得多. (3认同)
  • @KymikoLoco这是完全错误的.手册页中的示例是OP中的一个(其中`i`被初始化为`1`).在这里,`i`被初始化为`j`,这实际上证明了一个问题. (3认同)
  • @Yakk订单是手册页 - > SO回答.以下是2007年手册页的存档,其中明确列出了此示例.来自Ben S的评论是一个有趣的例子,有人建议存在的东西甚至没有检查它已经存在.http://web.archive.org/web/20070712184121/http://linux.die.net/man/1/gcc (2认同)
  • @jazzpi 嘿,你说得对。我检查并重新检查,但没有发现一个字符更改,因为我确定 codingdave 也错过了。无论如何,codingdave 是不正确的,它没有被引用,因为它不在手册页中。Ben S 实际上是正确的,它应该是一个示例(或 *the* 示例)。我错了,因为这个 SO 答案不在手册页中,过去或现在。 (2认同)
  • 为什么片段中的“ i”被初始化为未知值? (2认同)

Ste*_*sop 37

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

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

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


gkb*_*986 14

其他答案提供了一些很好的例子来证明警告的选择.我以为我会提供一些历史背景.C++的创建者Bjarne Stroustrup在他的"C++编程语言"(第3版,第259页)一书中解释道:

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


Pav*_*aev 9

如果您的初始化程序有副作用,这可能会咬你.考虑:

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

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

struct baz {
    int x, y;
    baz() : y(foo()), x(bar()) {}
};
Run Code Online (Sandbox Code Playgroud)

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

或者,如果xy某些用户定义类型具有构造函数,则该构造函数也可能具有副作用,具有相同的非显而易见的结果.

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


jal*_*alf 7

存在警告是因为如果您只是阅读构造函数,它看起来就像j之前被初始化一样i.如果用于初始化另一个,则会成为问题,如

struct A {
  int i;
  int j;
  A(): j (0), i (this->j) { }
};
Run Code Online (Sandbox Code Playgroud)

当你只看构造函数时,这看起来很安全.但实际上,j在用于初始化时尚未初始化i,因此代码将无法按预期工作.因此警告.