Оператор за безопасно движение по изключение

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

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 Лекции: Stephan T. Lavavej - Стандартна библиотека с шаблони (STL), 9 от n (препратки към rvalue) (видео и забележки и код на STL в коментарите).

Може също да искате да прочетете статиите на Дейв Ейбрахамс Вашата следваща задача… и Изключително подвижно!.

person gx_    schedule 29.08.2013