#c #gcc #clang #compiler-warnings
#c #gcc #clang #предупреждения компилятора
Вопрос:
Рассмотрим следующий фрагмент. Класс test
имеет член const a
и функцию-член, fun
которая возвращает a
. Список инициализации используется для инициализации a
в конструкторе. Однако в списке инициализации для инициализации используется лямбда-выражение a
с возвращаемым значением fun. Это приводит к различному поведению clang и gcc при компиляции и во время выполнения, в зависимости от уровня оптимизации. Ниже приведен фрагмент и различные выходные данные при компиляции и во время выполнения. Является ли это ожидаемым поведением gcc и clang?
#include <iostream>
class test{
public:
const int a;
test(): a([this](){return fun();}()) {}
int fun()
{
return a;
}
};
int main()
{
auto t = test();
std::cout << t.a << 'n';
return 0;
}
Время компиляции:
clang -5.0 -std=c 17 -Wall -Wextra -Weverything
lambda_in_initializer_list.cpp:7:15: warning: lambda expressions are incompatible with C 98
[-Wc 98-compat]
test(): a([this](){return fun();}()) {}
^
warning: 'auto' type specifier is incompatible with C 98 [-Wc 98-compat]
lambda_in_initializer_list.cpp:17:5: warning: 'auto' type specifier is incompatible with C 98
[-Wc 98-compat]
auto t = test();
^~~~
3 warnings generated.
clang -5.0 -std=c 17 -Wall -Wextra -Weverything -O1
lambda_in_initializer_list.cpp:7:15: warning: lambda expressions are incompatible with C 98
[-Wc 98-compat]
test(): a([this](){return fun();}()) {}
^
warning: 'auto' type specifier is incompatible with C 98 [-Wc 98-compat]
lambda_in_initializer_list.cpp:17:5: warning: 'auto' type specifier is incompatible with C 98
[-Wc 98-compat]
auto t = test();
^~~~
g -std=c 17 -Wall -Wextra -Wpedantic
No output
g -std=c 17 -Wall -Wextra -Wpedantic -O1
lambda_in_initializer_list.cpp: In function ‘int main()’:
lambda_in_initializer_list.cpp:18:20: warning: ‘t.test::a’ is used uninitialized in this function [-Wuninitialized]
std::cout << t.a << 'n';
~~^
Время выполнения:
clang -5.0 -std=c 17 -Wall -Wextra -Weverything
0
clang -5.0 -std=c 17 -Wall -Wextra -Weverything -O1
4196112
g -std=c 17 -Wall -Wextra -Wpedantic
Non deterministic output.
g -std=c 17 -Wall -Wextra -Wpedantic -O1
0
Комментарии:
1. Какое детерминированное значение вы ожидали?
2. У вас неопределенное поведение. Все результаты действительны
3. Конечно, это неправильный способ инициализации переменной. Я ожидал бы, что clang предупредит меня, а gcc предупредит меня не только при включении оптимизации. Я бы также ожидал, что программа выведет одно и то же значение независимо от уровня оптимизации.
4. Добро пожаловать на UB land. Компилятору не обязательно сообщать вам об этом, и разные реализации могут делать разные вещи. Вы даже можете получать разные данные при каждом запуске одного и того же двоичного файла.
5. -Мы все не очень хорошая идея
Ответ №1:
Я не совсем понял вопрос, но, похоже, вы на самом деле спрашиваете «почему gcc не предупредил вас, пока вы не включили оптимизацию».
Это известная вещь. Обнаружение неопределенного поведения в сложных случаях требует довольно больших усилий со стороны компилятора и часто выполняется только при оптимизации кода (поскольку компилятор в любом случае выполняет много работы). Просто кое-что, что следует иметь в виду, когда вы имеете дело с реальными компиляторами.