27

I have a class like below.

#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;
}

I am getting compilation error like this,

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>&)’

Is that the default copy constructor and assignment opertaor do not work in such case?

PS: I am using gcc version 4.6.3

polapts
  • 5,493
  • 10
  • 37
  • 49

4 Answers4

28

You can't copy atomics with a standard copy constructor, since all loads and stores must happen explicitly. You'll have to write your own copy constructor for Sequence which does some initialization of the form value_(rhs.value_.load()) (possibly with more relaxed memory ordering).

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • Can you edit and add a compiling code example? I fail to solve this problem, I have tried: `Sequence& operator=(const Sequence &other) { value_ = other.value_.load(); return *this; }` – Victor Lamoine Sep 28 '17 at 20:50
  • 1
    @VictorLamoine: No idea what you did, but the general approach [works](https://wandbox.org/permlink/ZsHPDqhrIiybq7qf). – Kerrek SB Sep 28 '17 at 21:35
  • 1
    For more details on how you might actually write a copy-constructor (with default `seq_cst` for loading the source, but then avoiding the cost of an atomic store into the object under construction), see [Copy constructor for classes with atomic member](https://stackoverflow.com/questions/19961043/copy-constructor-for-classes-with-atomic-member/46045691#46045691). Make sure this is really what you want to implement; copying around atomics is usually contrary to their purpose as shared state. – Peter Cordes Oct 13 '17 at 01:34
9

Atomic has deleted copy-ctor. So copy/move-ctors in your class are deleted.

n3337 12.8/11

An implicitly-declared copy/move constructor is an inline public member of its class. A defaulted copy/ move constructor for a class X is defined as deleted (8.4.3) if X has:

— a non-static data member of class type M (or array thereof) that cannot be copied/moved because overload resolution (13.3), as applied to M’s corresponding constructor, results in an ambiguity or a function that is deleted or inaccessible from the defaulted constructor,

ForEveR
  • 55,233
  • 2
  • 119
  • 133
7

Because there is no std::atomic<long int>::atomic(const std::atomic<long int>&) function, there is no way for the compiler to create a default copy constructor for the Sequence class. If you need a copy constructor for that class (and you do if you want Sequence secondSequence = firstSequence; to work) then you need to write one.

This behavior is required by the standard:

The atomic integral and address types are listed below. These types shall have standard layout. They shall have a trivial default constructor, A constexpr explicit value constructor, a deleted copy constructor, a deleted copy assignment operator, and a trivial destructor. These types shall support aggregate initialization syntax.

David Schwartz
  • 179,497
  • 17
  • 214
  • 278
4

I'd guess that choice to delete the copy constructor in the standard was for two reasons:

  • a load/store pair is required in general. Is there any way to enforce that this would be done when you don't control the callers of std::atomic?

  • What do you do if std::atomic<> type that you were using was one for which is_lock_free() is false (ie. a mutex is required in the implementation for that size integer type)? What copy semantics do you use for the mutex initialization? A mutex that ends up implicitly copied needs to be re-initialized since it could be unluckily copied in a locked state. I'd guess that std::mutex also has a deleted copy constructor because of this, and that pushes the requirement into std::atomic too.

Peeter Joot
  • 7,848
  • 7
  • 48
  • 82