c++ g++ -Wreorder的意义是什么?

lqfhib0f  于 2023-07-01  发布在  其他
关注(0)|答案(6)|浏览(187)

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.
8iwquhpp

8iwquhpp1#

考虑:

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

现在i被初始化为某个未知值,而不是零。
或者,i的初始化可能会产生一些副作用,对于这些副作用,顺序很重要。例如

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

pxy2qtax2#

问题是,有人可能会看到构造函数中的成员初始化器列表,并认为它们是按顺序执行的(首先是j,然后是i)。它们不是,它们是按照类中成员的定义顺序执行的。
假设你写了A(): j(0), i(j) {}。有些人可能会读到,并认为i最终的值为0。它没有,因为你用j初始化了它,它包含垃圾,因为它本身没有被初始化。
警告提醒您编写A(): i(j), j(0) {},希望它看起来更可疑。

tkqqtvp1

tkqqtvp13#

其他答案提供了一些很好的例子来证明警告的选择是正确的。我想我会提供一些历史背景。C++的创造者Bjarne Stroustrup在他的书The C++ programming language(第3版,第259页)中解释说:
成员的构造函数在包含类自己的构造函数体执行之前被调用。构造函数是按照它们在类中声明的顺序调用的,而不是按照它们在初始化器列表中出现的顺序。为了避免混淆,最好按声明顺序指定初始值设定项。成员析构函数按与构造相反的顺序调用。

jbose2ul

jbose2ul4#

如果你的初始化器有副作用的话,这可能会对你不利。考虑:

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是具有构造函数的用户定义类型,则该构造函数也可能具有副作用,并具有相同的非显而易见的结果。
当一个成员的初始化器引用另一个成员时,它也可以表现出来。

kqhtkvqz

kqhtkvqz5#

该警告存在的原因是,如果您只是读取构造函数,则看起来ji之前被初始化。如果其中一个被用来初始化另一个,这就成了一个问题,如

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

当你只看构造函数时,它看起来是安全的。但实际上,j在用于初始化i时尚未初始化,因此代码不会按预期工作。所以才有警告。

hzbexzde

hzbexzde6#

已经有很多很好的答案了,但是还有一件事没有解决-- * 为什么 * 初始化的顺序是这样的?
类成员的初始化顺序是不是初始化器在构造函数中列出的顺序,而是它们在类本身中声明的顺序。原因有点微妙。
C保证成员变量的销毁顺序与构造顺序相反。由于一个类可以有多个构造函数,它们具有不同的初始化列表,析构函数需要知道顺序,这将是一个很大的簿记问题,并引入不必要的开销。解决方案是强制每个构造函数对成员使用相同的初始化顺序,以便析构顺序也可以固定。
由于不能使用初始化器顺序,唯一的选择是使用声明顺序。
虽然C
以不同于初始化器列表的顺序初始化变量是完全法律的的,但这是可能的错误的非直观来源。警告让您知道要查找这些bug,或者重新排序初始化器列表以反映实际情况。

相关问题