Consider the following minimal working example:
#include <atomic>
int main() {
::std::atomic<bool> a = false;
}
Copy ctor and copy assignment of atomic are both explicitly deleted. However, this should invoke the ctor taking exactly a bool.
Both g++ and clang++ complain that this line is attempting to invoke the copy ctor of atomic
:
$ g++ -std=c++1z a.cpp
a.cpp: In function ‘int main()’:
a.cpp:4:27: error: use of deleted function ‘std::atomic<bool>::atomic(const std::atomic<bool>&)’
::std::atomic<bool> a = false;
^~~~~
$ clang++ -std=c++1z a.cpp
a.cpp:4:23: error: copying variable of type '::std::atomic<bool>' invokes deleted constructor
::std::atomic<bool> a = false;
^ ~~~~~
Why are they trying to copy an atomic
?
In C++, a Copy Constructor may be called for the following cases: 1) When an object of the class is returned by value. 2) When an object of the class is passed (to a function) by value as an argument. 3) When an object is constructed based on another object of the same class.
A class object with a constructor must be explicitly initialized or have a default constructor. Except for aggregate initialization, explicit initialization using a constructor is the only way to initialize non-static constant and reference class members.
When we create our own copy constructor, we pass an object by reference and we generally pass it as a const reference. One reason for passing const reference is, we should use const in C++ wherever possible so that objects are not accidentally modified.
Constructors for Initialization. Constructors for Initialization. A constructor must have the same name as the class. A constructor's function definition cannot return a value. No type, not even void, can be given at the start of the constructor's function prototype or in the function header.
It tries to invoke the copy constructor because its move constructor has been implicitly deleted.
Suppose we have a class X.
struct X
{
X(const X&) = delete; // user-declared
X(int)
{
}
};
Now, if you were to write
X x = 4;
it would be the same as
X x = X(4); // copy/move into x, see 15.6.1
and you would get a compilation error because you explicitly deleted the copy constructor and therefore no move constructor is being implicitly declared.
15.8.1 Copy/move constructors
[...]
If the definition of a class X does not explicitly declare a move constructor, a non-explicit one will be implicitly declared as defaulted if and only if
- X does not have a user-declared copy constructor,
- X does not have a user-declared copy assignment operator,
- X does not have a user-declared move assignment operator, and
- X does not have a user-declared destructor.
[ Note: When the move constructor is not implicitly declared or explicitly supplied, expressions that otherwise would have invoked the move constructor may instead invoke a copy constructor. — end note ]
In C++17 this changes with the introduction of guaranteed copy elision.
This results in the line being equal to
X x(4);
which does not rely on either copy or move constructor and instead calls X(int)
.
Like X, std::atomic also has its copy constructor explicitly deleted which is why your code fails to compile if not compiled with C++17 support.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With