为什么使用 C++17 禁用 std::atomic 的复制省略不起作用?



对于std::atomic,复制构造函数被删除,由于复制省略,这应该只能在c++ 17或更高版本中编译:

std::atomic<int> t_int = 1; 

我期望它不使用-fno-elide-constructors标志编译,但它仍然编译:

https://godbolt.org/z/nMvG5vTrK

为什么会这样?

c++ 17并没有简单地说以前可选的返回值优化现在是强制性的。语言的实际描述发生了变化,因此从一开始就不再创建临时对象了。

因此,从c++ 17开始,不再有可以省略的构造函数调用。因此,-fno-elide-constructors没有添加任何临时创建是有道理的。那是违反语言规则的。

在c++ 17之前,语言描述了创建一个临时对象,从该对象初始化变量,然后添加了编译器允许省略该临时对象。因此,无论是否使用-fno-elide-constructors,编译器省略或不省略临时副本都是符合标准的。

我希望它不会使用-fno-elide-constructors标志编译,

给定标志对返回值优化(也称为RVO)从c++ 17起没有影响。这是因为它不再被认为是一个优化(从c++ 17开始),而是一个语言保证.

From mandatory copy elison:

在下列情况下,编译器被要求省略类对象的复制和移动构造,即使复制/移动构造函数和析构函数具有可观察到的副作用。对象直接构造到存储中,否则它们将被复制/移动到中。。复制/移动构造函数不需要存在或可访问:

  • 在对象的初始化中,当初始化表达式为prvalue与变量类型相同的类类型(忽略cv-qualification):

(强调我的)

这意味着t_int是直接从prvalue1构造的。与NRVO不同,-fno-elide-constructors对RVO没有影响。因此,删除复制构造函数对您的情况没有影响。

也许一个例子可以帮助说明相同的,

struct Custom 
{
public:
Custom(int p): m_p(p)
{
std::cout<<"converting ctor called"<<std::endl;
}
Custom(const Custom&) = delete; //deleted copy ctor
private:
int m_p = 0;
};
int main()
{
Custom c = 1; //works in C++17 but not in Pre-C++17
}

最新更新