为什么要使用删除的rvalue引用构造函数?

时间:2017-03-31 05:37:09

标签: c++ c++11

这是A和B类的一个非常简单的例子。 我想只允许深度复制,所以我禁用了rvalue引用构造函数。

#include <iostream>

class B;

class A {
public:
    A();
    ~A();
    A(const A & other);
    A& operator=(const A & other);
    A(A && ) = delete;
    A& operator=(A && ) = delete;
    B toB() const;

private:
    int a_;
};

class B {
public:
    B();
    ~B();
    B(const B & other);
    B& operator=(const B & other);
    B(B && ) = delete;
    B& operator=(B && ) = delete;
    A toA() const;

private:
    int b_;
};

A::A()
{
}

A::~A()
{
}
A::A(const A & other)
        : a_(other.a_)
{
}
A& A::operator=(const A & other)
{
    a_ = other.a_;
    return *this;
}

B A::toB() const
{
    return B();
}

B::B()
{
}
B::~B()
{
}
B::B(const B & other)
        : b_(other.b_)
{
}
B& B::operator=(const B & other)
{
    b_ = other.b_;
    return *this;
}

A B::toA() const
{
    return A();
}


int main()
{
    A a();
    B b();

    return 0;
}

gcc编译器报告错误如下:

In member function 'B A::toB() const':
error: use of deleted function 'B::B(B&&)'
     return B();
              ^
note: declared here
     B(B && ) = delete;

我在徘徊为什么它使用B(B && )函数,而不是B(const B &)函数。

2 个答案:

答案 0 :(得分:4)

因为您添加了移动构造函数。删除但声明的函数仍然是类的接口的一部分。这意味着它将由编译器考虑,但由于它被标记为已删除,您将收到错误。如果要强制调用copy-constructor,请删除move-constructor声明。

来自this deleted functions reference

  

删除函数的任何使用都是格式错误的(程序不会编译)。这包括显式调用(使用函数调用运算符)和隐式调用(调用已删除的重载运算符,特殊成员函数,...

[强调我的]

由于删除的函数是接口的一部分,编译器将尝试使用它们。因此,当有一个删除的移动构造函数时,编译器会看到并尝试使用它,但由于它被删除会出现错误。

如果有一个显式的复制构造函数(根据this move constructor reference),编译器不会创建移动构造函数,只需使用默认的复制构造函数就会禁止移动对象。

所有这些意味着您的课程可以非常简化:

class A {
public:
    A() : a_() {}

    A(const A & other) = default;

    B toB() const;

private:
    int a_;
};

class B {
public:
    B() : b_() {}

    B(const B & other) = default;

    A toA() const;

private:
    int b_;
};

因为上面的类具有用户声明的复制构造函数,所以不会创建移动构造函数,并且只能复制该类。

答案 1 :(得分:1)

只要创建了无名对象,就会调用Move Constructor。

B A::toB() const函数中有一个语句return B();,它创建一个从函数返回的无名对象。要创建无名对象,需要删除移动构造函数。