Оператор безопасного перемещения исключений

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

template<class T>
CLArray<T>&
CLArray<T>::operator=( const CLArray& rhs )
{
    CLArray tmp( rhs );
    std::swap( size_, tmp.size_ );
    std::swap( data_, tmp.data_ );
    return *this;
}

Но как насчет назначения движения? Я имею в виду, если во время ЭТОЙ операции перемещения где-то еще в коде возникнет исключение, я потеряю состояние обоих объектов, верно? Поэтому мне пришлось бы сначала создать локальную копию, а затем удалить все, кроме только что созданного CLArray ...

template <class T>
CLArray<T>&
CLArray<T>::operator=( CLArray<T>&& rhs )
{
    size_ = rhs.size_;
    data_ = std::move( rhs.data_ );
    return *this;
}

Обратите внимание, что data_ — это std::vector, и спасибо за ответы!


person Athanase    schedule 29.08.2013    source источник


Ответы (2)


Действительно, может быть трудно или невозможно обеспечить гарантии исключения, если конструктор перемещения может вызвать исключение.

Я бы предложил поступить так, как это делает стандартная библиотека: задокументировать, что определенные операции имеют гарантии исключения (или, в некоторых случаях, разрешены только), если конструкция перемещения T не вызывает исключение. Обеспечение гарантии путем копирования объекта уничтожает преимущества перемещения-назначения для всех типов, а не только для тех (очень редких), которые могут вызвать выброс.

person Mike Seymour    schedule 29.08.2013
comment
Спасибо за ответ, я полностью понимаю, почему создание копии было бы глупо для назначения перемещения. - person Athanase; 29.08.2013

В любом случае вы должны добавить функцию-член swap и использовать конструкторы (копирование/перемещение) в операторах присваивания (копирование/перемещение). (И поместите операции, которые не могут бросить, после тех, которые могут.)

Пример (здесь встроенный в класс для краткости):

template<typename T>
class CLArray {
public:
    void swap( CLArray& other )
    {
        std::swap( data_, other.data_ );
        std::swap( size_, other.size_ );
    }

    CLArray( const CLArray& other )
        : data_( other.data_ ), size_( other.size_ )
    {
    }

    CLArray& operator=( const CLArray& rhs )
    {
        CLArray( rhs ).swap( *this );
        return *this;
    }

    CLArray( CLArray&& other )
        : data_( std::move( other.data_ ) )
    {
        size_ = other.size_;
        other.size_ = 0;
    }

    CLArray& operator=( CLArray&& rhs )
    {
        CLArray( std::move( rhs ) ).swap( *this );
        return *this;
    }

    // ...

private:
    std::vector<T> data_;
    std::size_t    size_;
};

См. C9 Lectures: Stephan T. Lavavej - Standard Template Library (STL), 9 of n (ссылки на rvalue) (видео и комментарии STL и код в комментариях).

Вы также можете прочитать статьи Дэйва Абрахамса Ваше следующее задание… и Исключительно трогательно!.

person gx_    schedule 29.08.2013