具有移动构造函数和赋值的类的默认复制构造函数和赋值

时间:2014-01-09 06:50:02

标签: c++ c++11 move-semantics

假设我有这门课程:

class Test
{
public:
    Test();
};

AFAIK,编译器提供默认的复制构造函数和赋值运算符,它将其他实例的每个成员分配给当前实例。现在我添加移动构造函数和赋值:

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

此类是否仍包含编译器生成的复制构造函数和赋值运算符,或者我需要实现它们?

修改即可。这是我的考验:

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;
}

打印2 12345 2 12345。编译器:VC ++ 2010.根据此测试,复制构造函数和赋值仍在此处。这是标准行为,我能确定这对每个C ++编译器都有效吗?

2 个答案:

答案 0 :(得分:7)

12.8-7复制和移动类对象[class.copy]

  

如果类定义没有显式声明复制构造函数,则会声明隐式。如果类定义声明了移动构造函数或移动赋值运算符,则隐式声明的复制构造函数被定义为已删除;否则,它被定义为默认值(8.4)。如果类具有用户声明的复制赋值运算符或用户声明的析构函数,则不推荐使用后一种情况...

来自 12.8-18

  

如果类定义没有显式声明一个复制赋值运算符,则会隐式声明一个。如果类定义声明了移动构造函数或移动赋值运算符,则隐式声明的复制赋值运算符被定义为已删除;否则,它被定义为默认值(8.4)。如果类具有用户声明的复制构造函数或用户声明的析构函数,则不推荐使用后一种情况...

根据这个,既然你已经声明了一个移动构造函数一个移动赋值运算符,但是没有复制赋值运算符,复制构造函数或析构函数,那么你可以来获取隐式生成的复制构造函数或赋值运算符。编译器为您提供了声明,但它们被声明为deleted

以下是您的示例的简化版本:

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

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

g ++ 4.8.1产生的错误

  

ctors.cpp:13:13:错误:使用已删除的函数'constexpr Test :: Test(const Test&amp;)'

     

测试t2(t1);

     

ctors.cpp:1:8:注意:'constexpr Test :: Test(const Test&amp;)'被隐式声明为已删除的,因为'Test'声明了一个移动构造函数或移动赋值运算符 < / p>      

struct Test

(强调我的)

答案 1 :(得分:1)

根据第12.8节复制和移动C ++标准的类对象

  

7如果类定义没有明确声明副本   构造函数,一个是隐式声明的。如果是类定义   声明一个移动构造函数或移动赋值运算符   隐式声明的复制构造函数被定义为已删除;除此以外,   它定义为默认值(8.4)。

     

18如果类定义没有明确声明副本   赋值运算符,一个是隐式声明的。如果上课   definition声明一个move构造函数或移动赋值运算符,   隐式声明的复制赋值运算符定义为   删除;否则,它被定义为默认值(8.4)。

因此,在您的情况下,复制构造函数和复制赋值运算符由编译器隐式声明,但定义为已删除。