【问题标题】:Exception safe move operator异常安全移动运算符
【发布时间】:2013-08-29 09:32:58
【问题描述】:

我通常(尝试)使用复制交换习语编写异常安全的复制赋值运算符,我想知道在编写移动赋值运算符时是否应该关注异常。 下面是一个复制赋值运算符的例子:

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,感谢您的回答!

【问题讨论】:

    标签: c++ move


    【解决方案1】:

    确实,如果移动构造函数可能抛出异常,则很难或不可能提供异常保证。

    我建议像标准库那样做:记录某些操作只有在 T 的移动构造没有抛出时才具有异常保证(或者,在某些情况下,只允许)。通过复制对象来确保保证会破坏所有类型的移动分配的好处,而不仅仅是可能抛出的(非常罕见的)那些。

    【讨论】:

    • 感谢您的回答,我完全明白为什么创建副本对于移动作业来说是愚蠢的。
    【解决方案2】:

    无论如何,您应该添加一个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 references)(视频和STL的备注和cmets中的代码)。

    您可能还想阅读 Dave Abrahams 的文章 Your Next Assignment…Exceptionally Moving!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-01-08
      • 2012-10-31
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多