有关swap()操作的异常安全性 - 这有什么问题?

JAN*_*JAN 10 c++ exception-handling exception exception-safety

我继续阅读该swap()操作,例如:

template<class T>
void swap (T &a, T &b)
{
  T temp (a);
  a = b;
  b = temp;
}
Run Code Online (Sandbox Code Playgroud)

当我们处理异常安全时会出现问题.

它有什么问题?此外,我们如何解决它?

Dav*_*eas 22

在一般实现中,假设Tcan的任何操作throw,您都不能提供强异常保证,这意味着在异常事件的操作之前完全保留状态.即使每个操作都T提供强大的异常保证:

template<class T>
void swap (T &a, T &b)
{
  T temp (a);          // [1]
  a = b;               // [2]
  b = temp;            // [3]
}
Run Code Online (Sandbox Code Playgroud)

如果[1]抛出,则输入保持不变,这很好.如果[2]抛出,并且假设强异常保证,则值仍未触及,这是好的.但是如果抛出的是[3],a则已经被修改,这意味着在异常传播到堆栈之后,调用者将留下既不是原始状态也不是最终状态的状态.


编辑:此外,我们如何解决它?

没有通用的解决方案.但在大多数情况下,您可以为swap类型提供异常安全操作.考虑一个vector<T>,在内部通过使用三个指针(管理它的状态begin,end,capacity).swap上面的一般可以抛出(无法分配,内部的构造函数T可能会抛出......),但提供一个无抛出的swap实现是微不足道的:

template <typename T>
class vector {
   T *b,*e,*c;
public:
   void swap( vector<T>& rhs ) {
      using std::swap;
      swap( b, rhs.b );
      swap( e, rhs.e );
      swap( c, rhs.c );
   }
//...
};
template <typename T>
void swap( vector<T>& lhs, vector<T>& rhs ) {
   lhs.swap(rhs);
}
Run Code Online (Sandbox Code Playgroud)

因为指针的复制不能抛出,所以swap上面提供了无抛出保证,如果你总是swap按照上面的模式实现(using std::swap;接着swap是非限定的调用),它将被ADL选中作为更好的匹配std::swap.