В чем смысл g++ -Wreorder?
опция g++ - Wall включает в себя-Wreorder. То, что делает этот параметр, описано ниже. Для меня не очевидно, почему кто-то будет заботиться (особенно достаточно, чтобы включить это по умолчанию в стене).
-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 ответов:
считаем:
struct A { int i; int j; A() : j(0), i(j) { } };
теперь
i
инициализируется до некоторого неизвестного значения, а не нуля.альтернативно, инициализация
i
может иметь некоторые побочные эффекты, для которых важен порядок. Е. Г.A(int n) : j(n++), i(n++) { }
проблема в том, что кто-то может увидеть список инициализаторов членов в конструкторе и подумать, что они выполняются в этом порядке (сначала j, затем i). Это не так, они выполняются в том порядке, в котором члены определены в классе.
Предположим, вы написали
A(): j(0), i(j) {}
. Кто-то может прочитать это и подумать, что я заканчиваю со значением 0. Это не так, потому что вы инициализировали его с помощью j, который содержит мусор, потому что он сам не был инициализирован.в предупреждение напоминает вам написать
A(): i(j), j(0) {}
, который, надеюсь, выглядит намного более подозрительным.
другие ответы предоставили несколько хороших примеров, которые оправдывают возможность предупреждения. Я подумал, что мог бы предоставить некоторый исторический контекст. Создатель C++, Бьярне Страуструп, объясняет в своей книге язык программирования C++ (3-е издание, стр. 259):
конструкторы членов вызываются до выполнения тела собственного конструктора содержащего класса. Конструкторы вызываются в том порядке, в котором они объявлены в классе, а чем порядок, в котором они появляются в списке инициализатора. Чтобы избежать путаницы, лучше всего указать инициализаторы в порядке объявления. Деструкторы элементов вызываются в обратном порядке построения.
Это может укусить вас, если ваш инициализаторы имеют побочные эффекты. Рассмотрим:
int foo() { puts("foo"); return 1; } int bar() { puts("bar"); return 2; } struct baz { int x, y; baz() : y(foo()), x(bar()) {} };
выше будет печатать "бар", а затем" foo", хотя интуитивно можно было бы предположить, что порядок записан в списке инициализаторов.
Если
x
иy
имеют некоторый пользовательский тип с конструктором, этот конструктор также может иметь побочные эффекты, с тем же неочевидным результатом.Он также может проявляться при инициализации для одного члена ссылается на другого участника.
предупреждение существует, потому что если вы просто читаете конструктор, это выглядит так:
j
инициализируется передi
. Это становится проблемой, если один используется для инициализации другого, как вstruct A { int i; int j; A(): j (0), i (this->j) { } };
когда вы просто смотрите на конструктор, это выглядит безопасная. Но на самом деле,
j
еще не был инициализирован в точке, где она используется для инициализацииi
, и поэтому код не будет работать как ожидалось. Отсюда и предупреждение.