Для правильной обработки копирования объектов эмпирическим правилом является правило трех. В C++11 важна семантика перемещения, поэтому вместо этого используется Правило пяти а>. Однако в обсуждениях здесь и в Интернете я также видел ссылки на Правило четырех (и половина), что является комбинацией правила пяти и идиомы копирования и замены.
Так что же такое Правило четырех (с половиной)? Какие функции необходимо реализовать и как должно выглядеть тело каждой функции? Какая функция является половиной? Есть ли недостатки или предупреждения для этого подхода по сравнению с правилом пяти?
Вот эталонная реализация, которая напоминает мой текущий код. Если это неверно, как будет выглядеть правильная реализация?
//I understand that in this example, I could just use `std::unique_ptr`.
//Just assume it's a more complex resource.
#include <utility>
class Foo {
public:
//We must have a default constructor so we can swap during copy construction.
//It need not be useful, but it should be swappable and deconstructable.
//It can be private, if it's not truly a valid state for the object.
Foo() : resource(nullptr) {}
//Normal constructor, acquire resource
Foo(int value) : resource(new int(value)) {}
//Copy constructor
Foo(Foo const& other) {
//Copy the resource here.
resource = new int(*other.resource);
}
//Move constructor
//Delegates to default constructor to put us in safe state.
Foo(Foo&& other) : Foo() {
swap(other);
}
//Assignment
Foo& operator=(Foo other) {
swap(other);
return *this;
}
//Destructor
~Foo() {
//Free the resource here.
//We must handle the default state that can appear from the copy ctor.
//(The if is not technically needed here. `delete nullptr` is safe.)
if (resource != nullptr) delete resource;
}
//Swap
void swap(Foo& other) {
using std::swap;
//Swap the resource between instances here.
swap(resource, other.resource);
}
//Swap for ADL
friend void swap(Foo& left, Foo& right) {
left.swap(right);
}
private:
int* resource;
};
if
вif (resource != nullptr) delete resource;
не нужен. - person alain   schedule 18.08.2017int*
, а затем хотеть глубокие копии? Наличие бесполезного конструктора по умолчанию кажется не лучшей идеей, особенно если он просто используется в нечетном конструкторе перемещения, который создаст еще один объект внутриstd::swap
. Не похоже на очевидную оптимизацию скорости, которой должен быть конструктор перемещения. Также оператор присваивания, возможно, вызывающийstd::swap
, кажется рекурсивным, когда перемещение подкачки назначает объекты... - person Bo Persson   schedule 18.08.2017