Exceptional C++ 精华代码—实现异常安全的Stack
Exceptional C++ 精华代码—实现异常安全的Stack
最近赶上15号台风过境,意外的休息了半天,于是重新读了一遍Exceptional C++,在网上找了一下书中关于实现异常安全的Stack的代码,但是基本上都组织的有些乱,于是将其整理一下,并加以自己的注释,希望对学习C++的朋友们有所帮助。
首先关于这段代码是以分离实现的方式组织的,真正的实现代码和接口类分离,首先是StackImpl实现,所有的内存操作相关的工作都移到这个类中实现的:
--Separate Implementation class---Implementation of StackImpl--
template <class T> class StackImpl
{
public :
StackImpl ( size_t size = 0 );
~ StackImpl ();
void Swap ( StackImpl & other ) throw ();
T* v_; // ptr to dynamic memory area
size_t vsize_ ; // capacity of v_
size_t vused_ ; // # of T's actually in use
private :
// private and undefined : no copying allowed
StackImpl ( const StackImpl & );
StackImpl & operator =( const StackImpl & );
};
构造函数和析构函数实现如下:
Constructor:
template <class T>
StackImpl <T >:: StackImpl ( size_t size )
: v_( static_cast <T*>
( size == 0 ? 0: operator new( sizeof (T)* size ) ) ),
vsize_ ( size ),
vused_ ( 0 )
{
}
Destructor:
template <class T>
StackImpl <T >::~ StackImpl ()
{
destroy ( v_ , v_+ vused_ );
operator delete ( v_ );
}
工具函数实现如下:
template < class T1 , class T2 > void construct (T1* p, const T2& val)
{
new (p) T1(val); // placement new
};
template <class T> void destroy ( T* p )
{
p ->~T();
}
template < class FwdIt > void destroy ( FwdIt first , FwdIt last )
{
while ( first != last )
{
destroy ( &* first );
++ first ;
}
}
template <class T>
void StackImpl <T >:: Swap ( StackImpl & other ) throw ()
{
swap ( v_ , other .v_ );
swap ( vsize_ , other . vsize_ );
swap ( vused_ , other . vused_ );
}
template <class T> void swap ( T& a, T& b )
{
T temp (a);
a = b;
b = temp ;
}
Swap() safely exchanges guts of a StackImpl object with another one This cannot throw (only assignment of pointers)!
真正的Stack实现代码如下, StackImpl作为Stack的成员出现:
--Separate Implementation class---Implementation of Stack--
Stack containing StackImpl member
template <class T> class Stack
{
public :
Stack ( size_t size = 0 );
~ Stack ();
Stack ( const Stack & );
Stack & operator =( const Stack & );
size_t Count () const ;
void Push ( const T& );
T& Top (); // if empty , throws exception
void Pop (); // if empty , throws exception
private :
StackImpl <T> impl_ ; // private implementation
};
Stack in HAS-A containment relationship to StackImpl
Alternative: Private inheritance (StackImpl's interface could be protected in this case)
构造函数,拷贝构造函数和拷贝复制函数实现如下:
Constructor:
template <class T> Stack <T >:: Stack ( size_t size =0)
: impl_ ( size )
{
}
Copy Constructor:
template <class T> Stack <T >:: Stack ( const Stack <T >& other )
: impl_ ( other . impl_ . vused_ )
{
while ( impl_ . vused_ < other . impl_ . vused_ )
{
construct ( impl_ .v_+ impl_ .vused_ , other . impl_ .v_[ impl_ . vused_ ]);
++ impl_ . vused_ ;
}
}
Copy Assignment:
template <class T>
Stack <T >& Stack <T >:: operator =( const Stack <T >& other )
{
Stack <T> temp ( other );
impl_ . Swap ( temp . imp_ ); // this can 't throw
return * this ;
}
Canonical form of copy assignment:"Create Temporary and Swap"idiom Strongly exception safe, provided non-throwing Swap() function Protected against self-assignment.Take code that might throw safely off to the side. When this has succeeded, modify the program state (and clean up) using only non-throwing operations.
计数函数实现如下:
template <class T>
size_t Stack <T >:: Count () const
{
return impl_ . vused_ ;
}
Push操作实现如下:
template <class T>
size_t Stack <T >:: Push ( const T& t )
{
if ( impl_ . vused_ == impl_ . vsize_ ) {
Stack temp ( impl_ . vsize_ * 2 + 1 );
while ( temp . Count () < impl_ . vsize_ )
{
temp . Push ( impl_ .v_[ temp . Count ()] );
}
temp . Push ( t );
impl_ . Swap ( temp . impl_ );
}
else
{
construct ( impl_ .v_ + impl_ .vused_ , t );
++ impl_ . vused_ ;
}
}
Pop操作实现如下:
template <class T> std :: auto_ptr <T> Stack <T >:: Pop ()
{
if ( impl_ . vused_ == 0 ) throw " empty stack ";
std :: auto_ptr <T> res = new T( impl_ .v_[ impl_ . vused_ - 1] );
--impl_ . vused_ ;
destroy ( impl_ .v_ + impl_ . vused_ );
return res;
}
auto_ptr assignment cannot fail,Trades off performance for exception safety.
总结
编写异常安全的C++代码的关键在于了解什么是异常安全的代码,以及什么时候可以抛出异常,什么时候不要抛异常,在这一点上C++和C#有很大区别,不要想当然!
对于C++有两个要求:
对于处理不了的异常要向外层抛出,不能随意丢弃。
对于发生异常的情况下,不应该有资源泄漏或者状态不一致。
希望本文对大家有所帮助。