2009-12-01 5 views
117

Опция g ++ -Wall включает -Wreorder. Эта опция описана ниже. Для меня это не очевидно, почему кто-то позаботится (особенно, чтобы включить это по умолчанию в -Wall).Какой смысл g ++ -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. 

ответ

195

Рассмотрим:

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

Теперь i инициализируется до некоторой неизвестной величины, не равна нулю.

В качестве альтернативы, инициализация i может иметь некоторые побочные эффекты, для которых порядок важен. Например.

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

Это действительно должно быть примером в документации. –

+3

спасибо. Поскольку большинство наших типов были типами POD с простыми инициализаторами, это не происходило со мной. Ваш пример намного лучше, чем пример руководства g ++. –

+0

Примером в этом ответе является ужасное смешение. Когда я протестировал это, я обнаружил, что 'i' был последовательно инициализирован ** до' 0', что делает его похожим на то, что ничего не ошибочно. Но если вы используете что-то вроде '100', вы видите, что' j' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' Я знаю, что это, вероятно, связано с компилятором, но я использую все настройки g ++, которые я получаю с Ubuntu, поэтому это должно быть обычным явлением. –

9

Это может укусить вас, если ваши инициализаторы имеют побочные эффекты. Рассмотрим:

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 имеют определенный пользовательский тип с конструктором, этот конструктор может также иметь побочные эффекты с таким же неочевидным результатом.

Он также может проявляться, когда инициализатор для одного члена ссылается на другой член.

29

Проблема в том, что кто-то может увидеть список инициализаторов-членов в конструкторе и подумать, что они выполнены в этом порядке (сначала, а затем i). Их нет, они выполняются в порядке, определяемом членами в классе.

Предположим, вы написали A(): j(0), i(j) {}. Кто-то может это прочитать, и думаю, что я заканчиваю значением 0. Это не так, потому что вы инициализировали его j, который содержит мусор, потому что он сам не инициализирован.

Предупреждение напоминает вам написать A(): i(j), j(0) {}, который, мы надеемся, выглядит намного более подозрительным.

+0

Выглядит/запах рыбный! :) Определенно, запах кода :) Спасибо за ваше четкое объяснение, которое прямо к делу. :) – Will

+0

Хорошо объяснил, это должен быть лучший ответ! – Aaron

+0

«... напоминает вам написать A(): i (j), j (0) {} ..." Я предлагаю вам напоминать вам изменить порядок членов класса в этом конкретном случае. –

5

Предупреждение существует, потому что, если вы только что прочитали конструктор, похоже, что j инициализируется до i. Это становится проблемой, если один используется для инициализации другого, как в

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

Когда вы только посмотрите на конструктор, это выглядит безопасной. Но на самом деле j еще не был инициализирован в точке, где он используется для инициализации i, поэтому код не будет работать должным образом. Отсюда предупреждение.

9

Другие ответы предоставили несколько хороших примеров, которые оправдывают вариант предупреждения. Я думал, что предоставил бы какой-то исторический контекст. Создатель C++, Бьерн Страуструп, объясняет в своей книге The C++ programming language (3-е издание, стр 259):

Члены Конструкторы вызываются перед телом объемлющего класса собственного конструктора выполняется. Конструкторы вызываются в том порядке, в котором они объявлены в классе, а не в порядке, в котором они отображаются в списке инициализаторов. Чтобы избежать путаницы, лучше указать инициализаторы в порядке объявления.Деструкторы-члены вызываются в обратном порядке построения.

 Смежные вопросы

  • Нет связанных вопросов^_^