Making a class non-copyable: Private undefined methods vs Deleted methods

旧街凉风 提交于 2019-12-23 14:40:54

问题


Prior to C++11, I saw code like this:

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

For C++11 (and later), I see code like this:

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

Do they behave identically? If not, please explain.

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


回答1:


They are similar in most respects, but differ in some others.

Consider the following external code trying to copy objects of the class:

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

Both of these versions will cause the above code to fail. At this point, though, the developer would look at the interface to see why. With the delete version, it's obvious that Car was not meant to be copied. With the private version, (at least without a comment), it raises a doubt whether the copy constructor was perhaps placed in the private section by accident.

Now consider member code trying to copy objects of the class:

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

The delete version fails like before. The private version is a link error. This raises an even greater doubt - it's not uncommon to forget to define a method that has been declared. Perhaps this is what's happened here? The delete version doesn't have this problem.

Edit Scott Meyers discusses this in Item 11 of Effective Modern C++ Prefer deleted functions to private undefined ones.




回答2:


=delete will give more meaningful error messages. An error message about a deleted function tells you that it doesn't exist and no one can create an object with said constructor. Saying it is private doesn't give that information - it just says the caller cannot call it, not that no one can.

Also, a deleted constructor will not behave differently if called from within/outside the class (since private constructors can be called from within the class).

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




回答3:


Note that the two snippets you posted give exactly the same error, that is something like:

'Car(const Car&)' is private within this context

This is because you defined the member methods as private in both cases.
If you want to appreciate the differences, you should rather have public deleted copy constructor and copy operator, that is:

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

This way, you will be informed that those member methods have been explicitly and intentionally deleted:

use of deleted function 'Car(const Car&)'

Setting them as private doesn't say explicitly I want to delete them.
As an example, it could have been done for you want to force the users of your class to use a factory method to create instances of that class.

Anyway, (no longer so) new features are not for free and using them in a way that is not the intended one won't give the expected benefits.




回答4:


Car& operator=(const Car&) = delete; is expressing explicitly "copy assignment prohibited".

= delete; can also be used for any function as described on Bjarne's blog:

struct Z {
    // ...

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


来源:https://stackoverflow.com/questions/39888012/making-a-class-non-copyable-private-undefined-methods-vs-deleted-methods

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!