异常安全的复制构造函数和拷贝赋值运算符函数

来源:互联网 发布:网络基础知识有哪些 编辑:程序博客网 时间:2024/05/29 02:52

异常安全性问题

  • 异常安全代码
    在出现异常的情况下仍然能够正确运行
  • 异常中立
    将所有的异常都转发给调用者
  • 永远不要在析构函数、重载运算符函数operator delete()或者operator delete[]中抛出异常
    在编写析构函数和内存释放函数时,要假设存在throw()这样的异常规范

以template < typename T > class Stack为例

template <typename T>class Stack{public:    Stack();    ~Stack();    Stack( const Stack & );    Stack & operator=( const Stack & );    size_t Count() const { return vused_; }    void Push( const T& t );    T & Top()    {        if ( 0 == vused_ )        {            throw "empty stack";        }        return v_[vused_-1];    }    void Pop()    {        if ( 0 == vused_ )        {            throw "pop from empty stack";        }        else        {            -- vused_;        }    }private:    T *NewCopy( const T *src,                size_t srcsize,                size_t destsize );    T * v_;    size_t vsize_;    size_t vused_;};

默认构造过程

template <typename T>Stack<T>::Stack()    : v_( new T[10] ),    vsize_( 10 ),    vused_( 0 ){}

析构过程

template <typename T>Stack<T>::~Stack(){    delete[] v_;}

辅助函数

template <typename T>T *Stack<T>::NewCopy( const T *src, size_t srcsize, size_t destsize ){    assert( destsize >= srcsize );    T *dest =   new T[destsize];    try    {        copy( src, src+srcsize, dest );    }    catch ( ... )    {        delete[] dest;        throw;    }    return dest;}

拷贝构造函数

template <typename T>Stack<T>::Stack( const Stack<T> &other )    : v_( NewCopy( other.v_, other.vsize_, other.vsize_ ) ),      vsize_( other.vsize_ ),      vused_( other.vused_ ){}

拷贝赋值过程

template <typename T>Stack<T> &Stack<T>::operator=( const Stack<T> &other ){    if ( this != &other )    {        T *v_new =  NewCopy( other.v_, other.vsize_, other.vsize_ );        delete[] v_;        v_ =    v_new;        vsize_ =    other.vsize_;        vused_ =    other.vused_;    }    return *this;}

Push()

template <typename T>void Stack<T>::Push( const T &t ){    if ( vused_ == vsize_ )    {        size vsize_new =    vsize_*2+1;        T *v_new =  NewCopy( v_, vsize_, vsize_ );        delete[] v_;        v_ =    v_new;        vsize_ =    vsize_new;    }    v_[vused_] =    t;    ++ vused_;}
  • 基本保证:如果在类型T中或者程序中其他的地方抛出了异常,对象不应该造成资源泄漏
  • 强保证:如果某个操作由于抛出异常而终止,那么程序的状态应该保持不变
  • 无异常抛出保证:无论什么情况下,函数都不会抛出异常

封装内存管理工作

template <typename T1, typename T2>void construct( T1 *p, const T2 &value ){    new (p) T1(value);}template <typename T>void destroy( T *p ){    p->~T();}template <typename T>void destroy( T first, T last ){    while ( first != last )    {        destroy( &*first );        ++ first;    }}template <typename T>class StackImpl{protected:    StackImpl( size_t size=0 )        : v_( static_cast<T *>( 0==size ? 0 : operator new( sizeof(T)*size ) ) ),          vsize_( size ),          vused_( 0 )    {    }    ~StackImpl()    {        destroy( v_, v_+vused_ );        operator delete( v_ );    }    void Swap( StackImpl & other ) throw()    {        swap( v_, other.v_ );        swap( vsize_, other.vsize_ );        swap( vused_, other.vused_ );    }    T *v_;    size_t vsize_;    size_t vused_;private:    StackImpl( const StackImpl & );    StackImpl & operator=( const StackImpl & );};

更好的Stack

template <typename T>class Stack : private StackImpl<T>{public:    Stack( size_t size=0 )        : StackImpl<T>( size )    { }    ~Stack();    Stack( const Stack &other )        : StackImpl<T>( other.vused_ )    {        while ( vused_ < other.vused_ )        {            construct( v_+vused_, other.v_[vused_] );            ++ vused_;        }    }    Stack & operator=( const Stack & other )    {        Stack temp( other );        Swap( temp );        return *this;    }    size_t Count() const    {        return vused_;    }    void Push( const T & )    {        if ( vused_ == vsize_ )        {            Stack temp( vsize_*2+1 );            while ( temp.Count() < vused_ )            {                temp.Push( v_[temp.Count()] );            }            temp.Push( t );            swap( temp );        }        else        {            construct( v_+vused_, t );            ++ vused_;        }    }    T & Top()    {        if ( 0 == vused_ )        {            throw "empty stack";        }        return v_[ vused_-1 ];    }    void Pop()    {        if ( 0 == vused_ )        {            throw "pop from empty stack";        }        else        {            -- vused_;            destroy( v_+vused_ );        }    }}

优雅的实现

假设在StackImpl中,属性为public

template <typename T>class Stack{public:    Stack( size_t size=0 )        : impl( size )    { }    ~Stack();    Stack( const Stack & other )        : impl( other.impl_.vused_ )    {        while ( impl_.vused_ < other.impl_.vused_ )        {            construct( impl_.v_+impl_.vused_, other.impl_.v_[impl_.vused_] );            ++ impl_.vused_;        }    }    Stack & operator=( const Stack & other )    {        Stack temp( other );        impl_.Swap( other.impl_ );        return *this;    }    size_t Count() const    {        return impl_.vused_;    }    void Push( const T& t )    {        if ( impl_.vused_ == impl_.vsize_ )        {            Stack temp( impl_.vsize_*2+1 );            while ( temp.Count() < impl_.vused_ )            {                temp.Push( impl_.v_[temp.Count()] );            }            temp.Push( t );            impl_.Swap( temp.impl_ );        }        else        {            construct( impl_.v_+impl_.vused_, t );            ++ impl_.vused_;        }    }    T &Top()    {        if ( 0 == impl_.vused_ )        {            throw "empty stack";        }        returm impl_.v_[ impl_.vused_-1 ];    }    void Pop()    {        if ( 0 == impl_.vused_ )        {            throw "pop from empty stack";        }        else        {            --impl_.vused_;            destroy( impl_.v_+impl_.vused_ );        }    }private:    StackImpl< T > impl_;};

安全的异常

指导原则

  • 永远不要在析构函数、重载的operator delete()或者operator delete[]()等函数中抛出异常:编写每个析构函数和内存释放函数时,都要假定在声明这些函数的时候使用了throw()异常规范
  • 通过RAII(“资源获得也就意味着初始化”)这种惯用法来分离资源的所有权和资源的管理权
  • 在每个函数中,将所有可能会抛出异常的代码放在一起,并进行安全处理,当确认这些代码所进行的工作都已经成功地完成时,才可以使用不会抛出异常的操作来修改程序的状态

参考资料:
《Exceptional C++中文版》

0 0
原创粉丝点击