polapts
polapts

Reputation: 5793

Error with copy constructor/assignment operator for a class which has std::atomic member variable

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

Upvotes: 30

Views: 23046

Answers (4)

Peeter Joot
Peeter Joot

Reputation: 8260

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.

Upvotes: 5

Kerrek SB
Kerrek SB

Reputation: 477150

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).

Upvotes: 31

ForEveR
ForEveR

Reputation: 55897

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,

Upvotes: 11

David Schwartz
David Schwartz

Reputation: 182779

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.

Upvotes: 8

Related Questions