Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does the initialisation of an object invoke the copy constructor?

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?

like image 510
bitmask Avatar asked Feb 20 '18 10:02

bitmask


People also ask

When copy constructor will be invoked?

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.

What is the need for initialization of object using constructor?

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.

Why is it necessary to pass an object by reference in a copy constructor?

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.

What does it mean to initialize a constructor?

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.


1 Answers

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.

like image 92
Axalo Avatar answered Sep 22 '22 16:09

Axalo