27

我有一个像下面这样的课程。

#include <atomic>

static const long  myValue = 0;

class Sequence
{

public:

    Sequence(long initial_value = myValue) : value_(initial_value) {}


private:

     std::atomic<long> value_;
};

int main()
{
         Sequence firstSequence;
         Sequence secondSequence = firstSequence;
         return 0;
}

我收到这样的编译错误,

test.cpp:21:36: error: use of deleted function ‘Sequence::Sequence(const Sequence&)’
test.cpp:5:7: error: ‘Sequence::Sequence(const Sequence&)’ is implicitly deleted because the default definition would be ill-formed:
test.cpp:5:7: error: use of deleted function ‘std::atomic<long int>::atomic(const std::atomic<long int>&)’

在这种情况下,默认的复制构造函数和赋值操作符是否不起作用?

PS:我使用的是 gcc 版本 4.6.3

4

4 回答 4

26

您不能使用标准复制构造函数复制原子,因为所有加载和存储都必须显式发生。您必须编写自己的复制构造Sequence函数来对表单进行一些初始化value_(rhs.value_.load())(可能使用更宽松的内存排序)。

于 2012-08-17T09:24:59.523 回答
8

Atomic 已删除 copy-ctor。因此,您班级中的复制/移动角色将被删除。

n3337 12.8/11

隐式声明的复制/移动构造函数是其类的内联公共成员。如果 X 具有以下属性,则类 X 的默认复制/移动构造函数被定义为已删除 (8.4.3):

— 类类型 M(或其数组)的非静态数据成员,因为重载决议 (13.3) 应用于 M 的相应构造函数,导致模棱两可或函数被删除或无法从默认构造函数,

于 2012-08-17T09:27:23.570 回答
7

因为没有std::atomic<long int>::atomic(const std::atomic<long int>&)函数,所以编译器无法为Sequence类创建默认的复制构造函数。如果您需要该类的复制构造函数(如果您想Sequence secondSequence = firstSequence;工作就这样做),那么您需要编写一个。

标准要求此行为:

下面列出了原子整数和地址类型。这些类型应具有标准布局。它们应该有一个普通的默认构造函数、一个 constexpr 显式值构造函数、一个已删除的复制构造函数、一个已删除的复制赋值运算符和一个普通的析构函数。这些类型应支持聚合初始化语法。

于 2012-08-17T09:22:11.803 回答
2

我猜想在标准中删除复制构造函数的选择有两个原因:

  • 通常需要一个加载/存储对。当您不控制 std::atomic 的调用者时,有什么方法可以强制执行此操作?

  • 如果您使用的 std::atomic<> 类型是 is_lock_free() 为假的类型(即,该大小整数类型的实现中需要互斥锁),您会怎么做?您对互斥锁初始化使用什么复制语义?最终被隐式复制的互斥体需要重新初始化,因为它可能在锁定状态下被不幸地复制。我猜想 std::mutex 也因此有一个已删除的复制构造函数,这也将要求推到了 std::atomic 中。

于 2013-03-22T20:45:22.377 回答