移动构造函数绕过复制构造函数

时间:2016-04-13 15:52:51

标签: c++ constructor

正如所料,以下内容无法编译:

class A {
public:
    A() = default;
    //A(A&&) = default;
    A(const A&) = delete;
    int x;
};

int main()
{
    auto a4 = A{}; // not ok, copy constructor is deleted
    auto a5 = A(); // not ok, copy constructor is deleted
    return 0;
}

但是如果添加了移动构造函数,即使显式删除了复制构造函数,那么以下代码也会编译:

class A {
public:
    A() = default;
    A(A&&) = default;
    A(const A&) = delete;
    int x;
};

int main()
{
    auto a4 = A{}; // now ok, even though copy constructor is deleted
    auto a5 = A(); // now ok, even though copy constructor is deleted
    return 0;
}

为什么不考虑删除的拷贝构造函数?

1 个答案:

答案 0 :(得分:4)

  

为什么不考虑删除的拷贝构造函数?

被认为是。它没有被使用,所以它delete d并不重要。该规则来自[dcl.fct.def.delete]:

  

除了声明它之外,隐式或显式引用已删除函数的程序是不正确的。    [注意: [...]如果是一个功能   重载,只有在通过重载决策选择函数时才会引用它。 [...] -end note]

auto a = A{};上的重载决策(在这种情况下,大括号与parens相同)找到两个构造函数候选者:

A(const A&);
A(A&& );

选择哪个候选人是最好的可行性"候选人来自[over.match.best]:

  

鉴于这些定义,可行函数F1被定义为比另一个可行函数更好的函数   F2如果[...],然后
   - [...]
   - 上下文是转换函数的初始化,用于引用的直接引用绑定(13.3.1.6)   对于函数类型,F1的返回类型是相同类型的引用(即左值或右值)   引用被初始化,F2的返回类型不是

移动构造函数与参数的引用(rvalue)相同,而复制构造函数则不是。因此,它是首选并被选为最佳可行候选者。由于重载决策未选择A(const A&),因此我们不会引用该构造函数,因此代码很好。

如果我们实际上使用了复制构造函数(例如A a(a5)), 实际上会尝试使用复制构造函数,这将是错误的。