const 成员初始化之前的用法,这是 gcc 和 clang 的预期行为吗?

Posted

技术标签:

【中文标题】const 成员初始化之前的用法,这是 gcc 和 clang 的预期行为吗?【英文标题】:Usage before initialization of const member, is this expected bahviour of gcc and clang? 【发布时间】:2019-03-08 20:44:55 【问题描述】:

考虑以下sn-p。 test 类有一个 const 成员 a 和一个返回 a 的成员函数 fun。初始化列表用于在构造函数中初始化a。然而,在初始化列表中,一个 lambda 用于初始化 a 并使用返回的 fun 值。这会导致 clang 和 gcc 在编译和运行时的不同行为,具体取决于优化级别。下面列出了 sn-p 以及编译和运行时的不同输出。这是 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

【问题讨论】:

您预期的确定性值是多少? 您有未定义的行为。所有结果均有效 当然这不是初始化变量的正确方法。我希望 clang 会警告我,而 gcc 不仅会在优化打开时警告我。无论优化级别如何,我还希望程序打印相同的值。 欢迎来到 UB 土地。编译器不必告诉你它,不同的实现可以做不同的事情。你甚至可以从同一个二进制文件的每次运行中得到不同的东西。 -Weverything 不是个好主意 【参考方案1】:

我不太明白一个问题,但您似乎实际上是在问“为什么 gcc 在您进行优化之前没有警告您”。

这是众所周知的事情。在复杂情况下检测未定义的行为需要在编译器方面付出很多努力,并且通常仅在优化代码时才完成(因为无论如何编译器都在做很多工作)。只是在处理现实生活中的编译器时要记住一些事情。

【讨论】:

【参考方案2】:

你有未定义的行为。您在初始化之前使用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;

您的编译器甚至会就您的代码向您发出警告。听他们说。警告是正确的,您的代码无效。

【讨论】:

Clang 没有就此向我发出警告。只有优化级别 1 的 gcc 警告我。 @user3457151 是的。编译器不需要找到人们期望的所有可能的警告。如果编译器发现一些奇怪的东西,它们只会帮助你。

以上是关于const 成员初始化之前的用法,这是 gcc 和 clang 的预期行为吗?的主要内容,如果未能解决你的问题,请参考以下文章

MSVC 导致静态 const 模板成员初始化失败

C++ const常量成员函数

RAII:在 const 方法中初始化数据成员

在 VS2008 和 GCC 中编译 static const int = X 的最佳代码

类的const成员

C++常成员变量