Должен ли идиома «Копировать и поменять» идиома «Копировать и переместить» в C ++ 11?

Как объяснено вэтот ответидиома копирования и замены реализована следующим образом:

class MyClass
{
private:
    BigClass data;
    UnmovableClass *dataPtr;

public:
    MyClass()
      : data(), dataPtr(new UnmovableClass) { }
    MyClass(const MyClass& other)
      : data(other.data), dataPtr(new UnmovableClass(*other.dataPtr)) { }
    MyClass(MyClass&& other)
      : data(std::move(other.data)), dataPtr(other.dataPtr)
    { other.dataPtr= nullptr; }

    ~MyClass() { delete dataPtr; }

    friend void swap(MyClass& first, MyClass& second)
    {
        using std::swap;
        swap(first.data, other.data);
        swap(first.dataPtr, other.dataPtr);
    }

    MyClass& operator=(MyClass other)
    {
        swap(*this, other);
        return *this;
    }
};

Имея значение MyClass в качестве параметра для operator =, параметр может быть создан либо конструктором копирования, либо конструктором перемещения. Затем вы можете безопасно извлечь данные из параметра. Это предотвращает дублирование кода и способствует безопасности исключений.

В ответе упоминается, что вы можете поменять или переместить переменные во временную. В первую очередь речь идет об обмене. Однако обмен, если он не оптимизирован компилятором, включает три операции перемещения и в более сложных случаях выполняет дополнительную дополнительную работу. Когда все, что вы хотите, этопереехать временный в назначенный объект.

Рассмотрим этот более сложный пример, включающийсхема наблюдателя, В этом примере я написал код оператора присваивания вручную. Акцент делается на конструкторе перемещения, операторе присваивания и методе обмена:

class MyClass : Observable::IObserver
{
private:
    std::shared_ptr<Observable> observable;

public:
    MyClass(std::shared_ptr<Observable> observable) : observable(observable){ observable->registerObserver(*this); }
    MyClass(const MyClass& other) : observable(other.observable) { observable.registerObserver(*this); }
    ~MyClass() { if(observable != nullptr) { observable->unregisterObserver(*this); }}

    MyClass(MyClass&& other) : observable(std::move(other.observable))
    {
        observable->unregisterObserver(other);
        other.observable.reset(nullptr);
        observable->registerObserver(*this);
    }

    friend void swap(MyClass& first, MyClass& second)
    {
        //Checks for nullptr and same observable omitted
            using std::swap;
            swap(first.observable, second.observable);

            second.observable->unregisterObserver(first);
            first.observable->registerObserver(first);
            first.observable->unregisterObserver(second);
            second.observable->registerObserver(second);
    }

    MyClass& operator=(MyClass other)
    {
        observable->unregisterObserver(*this);
        observable = std::move(other.observable);

        observable->unregisterObserver(other);
        other.observable.reset(nullptr);
        observable->registerObserver(*this);
    }
}

Очевидно, что дублированная часть кода в этом написанном вручную операторе присваивания идентична части конструктора перемещения. Вы могли бы выполнить обмен в операторе присваивания, и поведение было бы правильным, но оно потенциально могло бы выполнить больше перемещений и выполнить дополнительную регистрацию (в обмене) и отмену регистрации (в деструкторе).

Разве не имело бы смысла многократно использовать код конструктора перемещения?

private:
    void performMoveActions(MyClass&& other)
    {
        observable->unregisterObserver(other);
        other.observable.reset(nullptr);
        observable->registerObserver(*this);
    }

public:
    MyClass(MyClass&& other) : observable(std::move(other.observable))
    {
        performMoveActions(other);
    }

    MyClass& operator=(MyClass other)
    {
        observable->unregisterObserver(*this);
        observable = std::move(other.observable);

        performMoveActions(other);
    }

Мне кажется, что этот подход никогда не уступает своп-подходу. Правильно ли я считаю, что идиома «копировать и менять» будет лучше, чем идиома «копируй и двигай» в C ++ 11, или я упустил что-то важное?

Ответы на вопрос(3)

Ваш ответ на вопрос