使类不可复制:私有未定义方法与已删除方法

时间:2016-10-06 05:15:51

标签: c++ c++11 noncopyable

在C ++ 11之前,我看到了这样的代码:

class Car {
public:
  Car() {}
private:
  Car(const Car&);
  Car& operator=(const Car&);
};

对于C ++ 11(及更高版本),我看到如下代码:

class Car {
public:
  Car() {}
private:
  Car(const Car&) = delete;
  Car& operator=(const Car&) = delete;
};

他们的行为是否相同?如果没有,请解释。

参考:https://ariya.io/2015/01/c-class-and-preventing-object-copy

4 个答案:

答案 0 :(得分:5)

=delete会提供更有意义的错误消息。有关已删除函数的错误消息告诉您它不存在,并且没有人可以使用所述构造函数创建对象。说它是私人的并不能提供这些信息 - 它只是说呼叫者无法呼叫它,而不是没有人可以呼叫它。

此外,如果从类内部/外部调用,则删除的构造函数的行为将不同(因为可以从类中调用私有构造函数)。

https://godbolt.org/g/06R9AQ

答案 1 :(得分:5)

它们在大多数方面都相似,但在其他方面则不同。

考虑以下外部代码,试图复制该类的对象:

int main() {
    Car c;
    Car other{c};
}

这两个版本都会导致上述代码失败。不过,在这一点上,开发人员会查看界面以了解原因。对于delete版本,显然Car并不意味着要复制。对于private版本(至少没有评论),它会怀疑复制构造函数是否可能意外放在private部分中。

现在考虑尝试复制该类对象的成员代码:

void Car::foo() {
    Car c;
    Car other{c}; 
}

delete版本像以前一样失败了。 private版本是链接错误。这引起了更大的疑问 - 忘记定义已声明的方法并不罕见。也许这就是这里发生的事情? delete版本没有此问题。

编辑 Scott Meyers在Effective Modern C++ 的第11项中对此进行了讨论。首选已删除的功能为私有未定义的

答案 2 :(得分:4)

请注意,您发布的两个代码段会给出完全相同的错误,例如:

  

' Car(const Car&)'在这种情况下是私人的

这是因为您在两种情况下都将成员方法定义为私有 如果您想了解这些差异,您应该使用公共delete d复制构造函数和复制运算符,即:

class Car {
public:
  Car() {}
// private: <-- this should not be here
  Car(const Car&) = delete;
  Car& operator=(const Car&) = delete;
};

这样,您将被告知这些成员方法已被明确且有意删除

  

使用已删除的功能&#39; Car(const Car&amp;)&#39;

将它们设置为私有并不明确说明我想删除它们
例如,可能已经完成了您希望强制类的用户使用工厂方法来创建该类的实例。

无论如何,(不再如此)新功能不是免费的,并且使用它们的方式不是预期的,不会给出预期的好处

答案 3 :(得分:3)

Car& operator=(const Car&) = delete;明确表达&#34;禁止复制作业&#34;。

= delete;也可用于Bjarne blog所述的任何功能:

struct Z {
    // ...

    Z(long long);     // can initialize with an long long
    Z(long) = delete; // but not anything less
};