为啥即使删除了复制构造函数,std::atomic 也会从 C++17 编译?

Posted

技术标签:

【中文标题】为啥即使删除了复制构造函数,std::atomic 也会从 C++17 编译?【英文标题】:Why does std::atomic compile from C++17 even with a deleted copy constructor?为什么即使删除了复制构造函数,std::atomic 也会从 C++17 编译? 【发布时间】:2021-09-20 11:51:27 【问题描述】:

我有一个简单的代码:

#include <atomic>

int main()

    std::atomic<int> a = 0;

此代码在带有 -std=c++17 的 GCC 11.1.0 中编译良好,但在 -std=c++14 和 -std=c++11 时编译失败。

使用已删除的函数 std::atomic::atomic(const std::atomic&)

这是为什么呢?在 C++17 类中 std::atomic 仍然没有复制构造函数。为什么这段代码对 -std=c++17 有效?

当然我知道首选的样式是使用,但我只是好奇为什么上面的代码从 C++17 开始编译得很好。

【问题讨论】:

【参考方案1】:

从 C++17 开始,这样的copy elision 是有保证的。对于std::atomic&lt;int&gt; a = 0;a需要直接从0初始化。

注意:上面的规则没有指定优化:C++17 prvalues 和 temporaries 的核心语言规范与早期的 C++ 修订版根本不同:不再有临时复制/移动。描述 C++17 机制的另一种方式是“未实现的值传递”:纯右值被返回和使用,而无需实现临时值。

在 C++17 之前,即使复制/移动操作(从从 0 初始化的临时 std::atomic&lt;int&gt; 初始化 a)可能被优化(在 copy initialization 中),复制/移动构造函数仍然需要可访问。

最后一步通常是优化出来的,转换的结果直接在为目标对象分配的内存中构造,但是即使不使用适当的构造函数(移动或复制)也需要可访问。 (直到 C++17)

【讨论】:

以上是关于为啥即使删除了复制构造函数,std::atomic 也会从 C++17 编译?的主要内容,如果未能解决你的问题,请参考以下文章

std::atomic_int 出现“使用已删除函数”错误

std::atomic 作为类成员:使用 boost/python.hpp 时使用已删除的函数错误

为啥不能交换 std::atomic<T> ?

初始化 std::atomic_bool?

为啥标准库不以无锁方式为 8 字节以下的结构实现 std::atomic?

为啥 std::atomic<T>::is_lock_free() 不像 constexpr 一样是静态的?