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

Why disabling copy elision for std::atomic doesn't work using C++17?

对于 std::atomic 复制构造函数被删除,由于 :

这应该只能用 C++17 和更高版本编译
std::atomic<int> t_int = 1; 

我预计它不会使用 -fno-elide-constructors 标志进行编译,但它仍然可以编译:

https://godbolt.org/z/nMvG5vTrK

这是为什么?

C++17 并不仅仅说以前可选的 return 值优化现在是强制性的。语言的实际描述发生了变化,因此一开始就不再创建临时对象。

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

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

I expected that it does not compile using -fno-elide-constructors flag,

给定标志对 C++17 及以后的 return 值优化(又名 RVO)没有影响。这是因为它不再被视为优化(来自 C++17),而是 语言保证

来自mandatory copy elison

Under the following circumstances, the compilers are required to omit the copy and move construction of class objects, even if the copy/move constructor and the destructor have observable side-effects. The objects are constructed directly into the storage where they would otherwise be copied/moved to. The copy/move constructors need not be present or accessible:

  • In the initialization of an object, when the initializer expression is a prvalue of the same class type (ignoring cv-qualification) as the variable type:

(强调我的)

这意味着 t_int 是直接从 prvalue 1 构造的。标志 -fno-elide-constructors 对 RVO 没有影响,这与 NRVO 不同。所以被删除的复制构造函数对你的情况没有影响。

也许一个例子可能有助于说明相同的情况,

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
}