【问题标题】:Default copy constructor and assignment for class with move constructor and assignment具有移动构造函数和赋值的类的默认复制构造函数和赋值
【发布时间】:2014-01-09 06:50:01
【问题描述】:

假设我有这个课程:

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++ 编译器吗?

【问题讨论】:

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


    【解决方案1】:

    来自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&)'

    测试 t2(t1);

    ctors.cpp:1:8: 注意:'constexpr Test::Test(const Test&)' 被隐式声明为已删除 因为 'Test' 声明了移动构造函数或移动赋值运算符

    结构测试

    (强调我的)

    【讨论】:

    • 谢谢。请看一下我的问题 - 它已被编辑。这是否意味着 VC++ 编译器会生成非标准代码?
    • @AlexFarber 正确。仅供参考 g++4.8.1 给我ctors.cpp:30:15: error: use of deleted function 'constexpr Test::Test(const Test&amp;)' Test t2(t1);
    • @AlexFarber 根据标准,它应该编译。这是g++(见上面的评论)的想法,在这种情况下,它是正确的。
    • @AlexFarber 我添加了一个简化的示例,带有非常有用的 gcc 错误消息(这些诊断在 gcc 的最新版本中得到了很大改进)。
    • @ildjarn 当然不符合标准。根据定义,不符合标准要求的实现是不符合标准的。当然,期望在规范之前发布的编译器符合该规范是荒谬的,但这并不会改变术语“不符合”的含义。
    【解决方案2】:

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

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

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

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

    【讨论】:

      猜你喜欢
      • 2016-09-13
      • 2013-03-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-02-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多