我注意到我的生产 C++17 代码中关于通用 lambda 和注释的行为不一致。我终于能够将其分解为以下最小示例。
为 x86_64 gcc 9.3 提供注释,但不为 x86_64 gcc 10.1 提供注释
#include <string>
#include <iostream>
struct STR { int a; };
int main()
{
auto lambda =
[]( const auto& executionContext )
{
if ( !executionContext.empty() )
return;
STR objSTR;
objSTR.a = 666;
std::cout << objSTR.a;
};
lambda( std::string{} );
return 0;
}
编译器消息如下:
<source>: In instantiation of 'main()::<lambda(const auto:1&)> [with auto:1 = std::__cxx11::basic_string<char>]':
<source>:19:31: required from here
<source>:4:12: note: 'struct STR' has no user-provided default constructor
4 | struct STR { int a; };
| ^~~
<source>:4:22: note: and the implicitly-defined constructor does not initialize 'int STR::a'
4 | struct STR { int a; };
| ^
这张纸条有什么用?我用 666 正确初始化了我的结构。 据我所知,这是正确的 C++ 代码,不需要任何关于可能未初始化的危险的注释/参考。
有趣的是,如果我现在将
auto
替换为 std::string
,则注释会完全消失。那么突然这里就不需要注释了?
对于 x86_64 gcc 9.3 和 x86_64 gcc 10.1 没有给出任何说明
#include <string>
#include <iostream>
struct STR { int a; };
int main()
{
auto lambda =
[]( const std::string& executionContext )
{
if ( !executionContext.empty() )
return;
STR objSTR;
objSTR.a = 666;
std::cout << objSTR.a;
};
lambda( std::string{} );
return 0;
}
如果我按如下方式使用值初始化,我只能删除通用 lambda 的注释:
对于 x86_64 gcc 9.3 和 x86_64 gcc 10.1 没有给出任何说明
#include <string>
#include <iostream>
struct STR { int a; };
int main()
{
auto lambda =
[]( const auto& executionContext )
{
if ( !executionContext.empty() )
return;
STR objSTR{}; //FORCED to add {} to get rid of the note
objSTR.a = 666;
std::cout << objSTR.a;
};
lambda( std::string{} );
return 0;
}
对我来说,当您在模板上下文(如通用 lambda)中不想使用此注释时,突然被迫对简单结构使用值初始化时,感觉就像是一个错误。事实上,该注释不再出现在 GCC 10.1 的上下文中,这一事实对我来说强调了这一论点。
具体、明确的问题是:
=> 你能确认这是 GCC 9.3 中的一个错误吗?
在线演示:https://godbolt.org/z/E7xeP91xd
标志: -Wall -Wextra -O3 -std=c++17
编译器:x86_64 gcc 9.3/x86_64 gcc 10.1
GCC 9.3 中关于 struct STR 中未初始化成员的注释在技术上是正确的,因为默认构造函数不会初始化 int a。
GCC 10.1 可能放宽了此检查或改进了通用 lambda 的上下文感知。使用 {} 初始化 objSTR 是确保初始化成员的好习惯。 如果该注释很烦人但无害,您可以安全地忽略它或显式初始化该结构。不同的编译器版本通常在警告和注释行为方面存在差异,这可以解释观察到的不一致情况。
GCC 9.3 在这里行为不正确吗?我知道我的结构没有初始化
int STR::a
不,即使您不在程序中的任何地方使用未初始化的成员,编译器也可以给出诊断(包括警告)。