Exception C++中讨论的异常安全栈,封装内存管理的版本,使用"成员变量"的方式实现

来源:互联网 发布:真伸缩金刚狼爪子淘宝 编辑:程序博客网 时间:2024/05/21 10:01
 

#include <new>

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 FwdIter>
void destroy(FwdIter first,FwdIter last)
{
 while (first != last)
 {
  destroy(&*first);
  ++first;
 }
}

template <class T>
void swap(T& a,T& b)
{
 T temp(a); a=b;b=temp;
}

template<class T>
class StackImpl
{
public:
 StackImpl(size_t size):
   v_(static_cast<T*>
    (size == 0 ? 0 :operator new (sizeof(T)*size))),
    vused_(0),
    vsize_(size)
 {}// new operator

 ~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& other);
 StackImpl& operator=(const StackImpl& other);


};

template<class T>
class Stack
{
public:
 Stack(size_t size=0):impl_(size)
 {}

 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(temp.impl_);
  return *this;
 }

 ~Stack()
 {
 }

 bool Empty()
 {
  return 0 == impl_.vused_;
 }

 size_t Count()const
 {
  return impl_.vused_;
 }

 void Push(const T& t)
 {
  if(impl_.vused_ == impl_.vsize_)
  {
   Stack temp(2*impl_.vsize_ + 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_;
  }

 }

 void Pop()
 {
  if (impl_.vused_ == 0)
  {
   throw "pop from empty stack";
  }
  else
  {
   --impl_.vused_;
   destroy(impl_.v_+impl_.vused_);
  }
 }

 T& Top()
 {
  if (impl_.vused_ == 0)
  {
   throw "empty stack";
  }
  return impl_.v_[impl_.vused_-1];
 }

private:
 StackImpl<T> impl_;

};

 

说明:使用StackImpl封装内存管理,Stack对外提供接口实现。

如果没有特殊的要求,比如基类对象要优先初始化,或者覆盖基类的虚函数,优先使用最后一个组合的版本实现栈。

这两个使用了StackImpl版本的优点是:

对T的要求只有两个:(1)T的析构函数不抛异常;(2)T有copy constructor;

而第一个简单版本对T的要求:除上面二者外,还需要default constructor and Exception-safe 's copy assignment.

明显后续两个版本的实现对T的要求更少,更利于Stack容器的复用。

 

在C++标准库中的容器和迭代器而言,除了多元素插入不是强异常安全的,还有vector<T>,deque<T>不是的插入和删除不是强异常安全的,其余都是强异常安全的。

对于这两个例外,可以使用temp and swap的方式来实现。

原创粉丝点击