21

オブジェクトのコピーを適切に処理するための経験則は、Rule of Threeです。C++11 では、ムーブ セマンティクスが問題になるため、代わりにRule of Five を使用します。ただし、ここやインターネットでの議論では、Rule of Five と copy-and-swap のイディオムを組み合わせたRule of Four (and a half)への言及も見ました。

では、4 (半) のルールとは正確には何ですか? どの関数を実装する必要があり、各関数の本体はどのように見えるべきですか? 半分はどの機能ですか?ルール・オブ・ファイブと比較して、このアプローチの欠点や警告はありますか?

これは、私の現在のコードに似た参照実装です。これが正しくない場合、正しい実装はどのようになりますか?

//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;
};
4

3 に答える 3