2017-02-08 6 views
9

Рассмотрим следующий код:Почему int a; а = станд :: макс (а, х) не выделяет «неинициализированные» предупреждения

#include <vector> 
#include <algorithm> 
#include <iostream> 

int main() { 
    std::vector<int> v{{1, 2, 3}}; 
    int a; 

    std::cout << a << std::endl; // 1 

    for (const int x : v) { 
     a = std::max(a, x);   // 2 
    } 

    std::cout << a << std::endl; 

    return 0; 
} 

По мере роста современных компиляторов и теперь внимательно следить над глупыми программиста ошибок, они отслеживают униализованные переменные. Однако этот код на C++ смущает их. До сих пор я получаю следующие результаты:

     (1)  (2) 
g++ 5.3.1 
clang++ 3.7    ✔ 
Solaris Studio 12.5  ✔ 

Как вы можете видеть, лязг и solstudio может обнаружить только случай (1) и игнорирующие случай (2), в то время как г ++ игнорирует оба. Есть ли осложнение для его обнаружения в случае (2)? Почему g ++ так плохо?

Опция компилятора я использовал:

$ g++-5 -std=c++11 -Wall -Wpedantic -pedantic -Wextra \ 
     -Wuninitialized -Wmaybe-uninitialized aisa.cpp 
$ clang++ -std=c++11 -Wall -Wpedantic -pedantic -Wextra -Wuninitialized aisa.cpp 
$ CC -std=c++11 -xprevise aisa.cpp 
+0

Рассмотрите возможность подачи запроса функции как на gcc, так и на clang-трекеры - такие тривиальные ситуации, как этот, вероятно, можно обнаружить с помощью дополнительной логики –

+2

Что произойдет, если вы удалите первый пример? Разве clang или Solaris Studio предупреждают об унифицированной переменной? –

+0

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

ответ

3

Прежде всего: оба компилятора только диагностируют первое нарушение, то есть сообщают только о первом неинициализированном использовании a. Таким образом, чтобы получить предупреждение для второго, нам нужно удалить эту первую строку:

#include <vector> 
#include <algorithm> 
#include <iostream> 

int main() { 
    std::vector<int> v{{1, 2, 3}}; 
    int a; 

    for (const int x : v) { 
     a = std::max(a, x);   // 2 
    } 

    std::cout << a << std::endl; 

    return 0; 

} 

Теперь мы видим две несвязанные причуды компилятора: лязгом не включает -Wconditional-uninitialized в -Wall и -Wextra. Если вы включите его, вы получите do, чтобы получить предупреждение на std::cout, поскольку оно потенциально печатает неинициализированную переменную.

gcc с другой стороны только отслеживает неинициализированные переменные, когда оптимизатор включен, возможно, для ускорения компиляции отладочных сборников. С -O2 -Wall gcc 6 выдает предупреждение в обоих случаях, хотя без указания местоположения точно так же, как clang делает во втором случае. (gcc < = 5.3 не предупреждает о втором случае, как вы заметили, так что, похоже, это было реализовано недавно.)

Итак, TL: DR: Вы не ссылались на свои компиляторы правильно.

+0

«Первое нарушение» означает первое появление конкретного предупреждения, не так ли? Не предупреждение вообще? –

+0

@QPaysTaxes Да. Не стесняйтесь редактировать, если вы можете заявить это более четко. –

+0

Да, я использовал g ++ 5. Спасибо за ваш ответ! – myaut

12

std::max берет свои аргументы const &, в то время как потоковый оператор << для int с принимает int по значению. Передача неинициализированного объекта по ссылке является законной: например, если функция просто берет свой адрес, все хорошо. Поэтому предупреждение при прохождении a до std::max может быть легко ложным.

+1

Было бы разумно не предупреждать, если это касается ссылки. Но это константная ссылка. Я думаю, что это будет ситуация, в которой компилятор мог бы предупредить, так как вы не можете инициализировать объект, переданный ссылкой на const. –

+1

@MarTijn Что, если единственная цель этой функции заключалась в том, чтобы принять 'const *' для объекта и использовать его в качестве ключа карты? Вы можете сделать это из 'const &', и вы можете сделать это даже из неинициализированного объекта. – Angew

+0

@MarTijn: Если функция сохраняет адрес объекта, то что-то позже может инициализировать переменную.(Или функция может использовать только адрес как своего рода уникальный тег). –