8

I have a class A with a member variable _atomicVar of type std::atomic<int>.

#include <atomic>

class A
{
public:
    A();
    ~A();

private:
    std::atomic<int> _atomicVar;
};

If I build the project I get the following error:

error C2280: 'std::atomic<int>::atomic(const std::atomic<int> &)' : attempting to reference a deleted function

I'm mainly a C# developer so I don't know every detail of C++ (yet). I don't know where I use the copy c'tor of atomic<int>.
I also tried to initialize _atomicVar:

std::atomic<int> _atomicVar { 0 };

... but that didn't work.
I would expect that _atomicVar (without an explicit initialization) would get initialized with the default value for int.
Can you tell me why this error occurs?

TorbenJ
  • 4,462
  • 11
  • 47
  • 84
  • You seem to be using Visual Studio. Which version? Also on what line of code you get the error? – Anton Savin Mar 29 '15 at 18:18
  • 2
    Is it your entire code? Perhaps you are copying `A` objects? Maybe you use a container that requires `CopyConstructible` elements? – zch Mar 29 '15 at 18:19
  • 2
    Simply not defining copy constructor is enough reason for this to happen. When you define types, that contain `atomic` members, you have to explicitly define valid semantic for all implicit operations, that can be performed or inserted by the compiler. – Mateusz Grzejek Mar 29 '15 at 18:24

1 Answers1

16

That's because copy constructor of std::atomic is deleted.

See this documentation page.

Since you do not define explicit copy constructor for A, compiler generates default one, which simply calls copy constructors for all members (which is not allowed for std::atomic).

Solution:

class A
{
public:
    A();
    A(const A& origin); // add this line
    ~A();
private:
    std::atomic<int> _atomicVar;
};

A::A(const A& origin)
: _atomicVar(0) //zero-initialize _atomicVar
{
}

EDIT

If you wonder, why atomic types are not copyable, you may want to read this question, especially accepted answer. If you want to copy value of std::atomic, you can do it:

A::A(const A& origin)
: _atomicVar(origin._atomicVar.load())
{
}

But keep in mind, that this operation itself will not be an atomic one (and, for most logics, meaningless).

Also, you may also want to define explicit assignment operator (remember about Rule of Three).

The best option for proper behaviour of your program would be deleting these two methods:

class A
{
public:
    A();
    A(const A&) = delete;
    ~A();

    A& operator=(const A&) = delete;

private:
    std::atomic<int> _atomicVar;
};

If your compiler doesn't support this (e.g. any VC before VC12), declare them as private and do not provide a body:

class A
{
public:
    A();
    ~A();

private:
    //do not define these two
    A(const A&);
    A& operator=(const A&);

private:
    std::atomic<int> _atomicVar;
};
Community
  • 1
  • 1
Mateusz Grzejek
  • 11,698
  • 3
  • 32
  • 49
  • 4
    Ehm I would not do this — now `A`'s copy semantics are broken. I'd instead `delete` `A`'s copy constructor. – Lightness Races in Orbit Mar 29 '15 at 18:33
  • 1
    Yes, you're right. I was already updating my answer when you wrote this. – Mateusz Grzejek Mar 29 '15 at 18:40
  • Thank you @MateuszGrzejek this really helped me, i have a class that was instantiated using a shared_ptr, and the class itself held a unique_ptr for a forward declaration, i didn't understand the error i was getting at first since i provided a default destructor needed to use a forward declaration in a unique_ptr, after reading this and create a additional copy constructor to the class to set the unique_ptr nullptr until the right constructor was called, my code worked, so thanks for a good answer helped alot (= – daniel Dec 13 '16 at 09:33