Использование перед инициализацией элемента const, это ожидаемое поведение gcc и clang?

#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 не предупредил вас, пока вы не включили оптимизацию».

Это известная вещь. Обнаружение неопределенного поведения в сложных случаях требует довольно больших усилий со стороны компилятора и часто выполняется только при оптимизации кода (поскольку компилятор в любом случае выполняет много работы). Просто кое-что, что следует иметь в виду, когда вы имеете дело с реальными компиляторами.