Использование перед инициализацией const member, это ожидаемый bhaviour gcc и clang? - PullRequest
0 голосов
/ 08 марта 2019

Рассмотрим следующий фрагмент. Класс test имеет константный член 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;
}

Compiletime:

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

Ответы [ 2 ]

3 голосов
/ 09 марта 2019

Я не совсем понял вопрос, но похоже, что вы на самом деле спрашиваете, «почему gcc не предупредил вас, пока вы не включили оптимизацию».

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

2 голосов
/ 08 марта 2019

У вас неопределенное поведение. Вы используете значение a до инициализации. Если вы хотите, чтобы ваша программа была действительной, инициализируйте переменную перед ее использованием.

struct test {
    int a;

    test(): a(0) { //     Effectively return the value of a,
                   //     which is 0 at this point.
        //          ~~~~~~~v~~~~
        a = [this]{ return fun(); }();
    }

    int fun()
    {
        return a;
    }
};

int main()
{
    auto t = test();
    std::cout << t.a << '\n';
    return 0;
}

Ваши компиляторы даже предупреждали вас о вашем коде. Слушай их. Предупреждение было правильным, ваш код неверен.

...