Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Default copy constructor and assignment for class with move constructor and assignment

Let's say I have this class:

class Test
{
public:
    Test();
};

AFAIK, compiler provides default copy constructor and assignment operators, which assign every member of other instance to the current instance. Now I add move constructor and assignment:

class Test
{
public:
    Test();
    Test(Test&& other);
    Test& operator=(Test&& other);
};

Does this class still contain compiler-generated copy constructor and assignment operators, or I need to implement them?

Edit. This is my test:

class Test
{
public:
    Test(){}

    Test(Test&& other){}
    Test& operator=(Test&& other)
    {
        return *this;
    }

    int n;
    char str[STR_SIZE];
};

int main()
{
    Test t1;
    t1.n = 2;
    strcpy(t1.str, "12345");

    Test t2(t1);

    Test t3;
    t3 = t1;

    cout << t2.n << " " << t2.str << " " << t3.n << " " << t3.str << endl;

    return 0;
}

Prints 2 12345 2 12345. Compiler: VC++ 2010. According to this test, copy constructor and assignment are still here. Is this standard behavior, can I be sure that this will work on every C++ compiler?

like image 729
Alex F Avatar asked Jan 09 '14 06:01

Alex F


2 Answers

From 12.8-7 Copying and moving class objects [class.copy]

If the class definition does not explicitly declare a copy constructor, one is declared implicitly. If the class definition declares a move constructor or move assignment operator, the implicitly declared copy constructor is defined as deleted; otherwise, it is defined as defaulted (8.4). The latter case is deprecated if the class has a user-declared copy assignment operator or a user-declared destructor...

From 12.8-18

If the class definition does not explicitly declare a copy assignment operator, one is declared implicitly. If the class definition declares a move constructor or move assignment operator, the implicitly declared copy assignment operator is defined as deleted; otherwise, it is defined as defaulted (8.4). The latter case is deprecated if the class has a user-declared copy constructor or a user-declared destructor...

According to this, since you have declared a move constructor and a move assignment operator, but no copy assignment operator, copy constructor or destructor, you do not get the implicitly generated copy constructor or assignment operator. The compiler gives you their declarations, but they are declared as deleted.

Here is a simplified version of your example:

struct Test
{
public:
    Test(){}
    Test(Test&& other){}
    Test& operator=(Test&& other) { return *this;}
};

int main()
{
  Test t1;
  Test t2(t1);
}

And the error produced by g++ 4.8.1

ctors.cpp:13:13: error: use of deleted function 'constexpr Test::Test(const Test&)'

Test t2(t1);

ctors.cpp:1:8: note: 'constexpr Test::Test(const Test&)' is implicitly declared as deleted because 'Test' declares a move constructor or move assignment operator

struct Test

(emphasis mine)

like image 77
juanchopanza Avatar answered Oct 26 '22 10:10

juanchopanza


According to section 12.8 Copying and moving class objects of the C++ Standard

7 If the class definition does not explicitly declare a copy constructor, one is declared implicitly. If the class definition declares a move constructor or move assignment operator, the implicitly declared copy constructor is defined as deleted; otherwise, it is defined as defaulted (8.4).

18 If the class definition does not explicitly declare a copy assignment operator, one is declared implicitly. If the class definition declares a move constructor or move assignment operator, the implicitly declared copy assignment operator is defined as deleted; otherwise, it is defined as defaulted (8.4).

So in your case and the copy constructor and the copy assignment operator are implicitly declared by the compiler but defined as deleted.

like image 1
Vlad from Moscow Avatar answered Oct 26 '22 09:10

Vlad from Moscow