强保证方法称为强保证方法

时间:2010-09-20 14:37:07

标签: c++ exception exception-handling

当我有一个方法调用一组提供强有力保证的方法时,我常常遇到回滚更改的问题,以便也有一个强大的保证方法。我们来举个例子:

// Would like this to offer strong guarantee
void MacroMethod() throw(...)
{
  int i = 0;
  try
  {
    for(i = 0; i < 100; ++i)
       SetMethod(i); // this might throw
  }
  catch(const std::exception& _e)
  {
    // Undo changes that were done
    for(int j = i; j >= 0; --j)
      UnsetMethod(j); // this might throw
    throw;
  }
}

// Offers strong guarantee
void SetMethod(int i) throw(...)
{
  // Does a change on member i
}

// Offers strong guarantee
void UnsetMethod() throw(...)
{
  // Undoes a change on member i
}

显然,UnsetMethod可能会抛出。在这种情况下,我的MacroMathod()仅提供基本保证。然而,我尽我所能提供强有力的保证,但我不能绝对确定我的UnsetMethod()不会抛出。这是我的问题:

  1. 在这种情况下,我是否应该尝试提供强有力的保证?
  2. 我应该将我的MacroMethod()记录为具有基本或强有力的保证吗?即使UnsetMethod不太可能抛出?
  3. 你能看到一种让这种方法真正提供强有力保证的方法吗?
  4. 我应该尝试调用UnsetMethod(),但感觉相当沉重,我该怎么做?
  5. 谢谢!

4 个答案:

答案 0 :(得分:6)

尝试实现此目的的一个好方法是使您的方法在您要修改的对象的副本上工作。完成所有修改后,您可以交换对象(应保证交换不要抛出)。这只有在有效实施复制和交换时才有意义。

此方法的优点是代码中不需要任何try...catch - 块,也没有清理代码。如果抛出异常,则在堆栈展开期间会丢弃修改后的副本,并且根本不会修改原始版本。

答案 1 :(得分:1)

如果强烈的异常保证对MacroMethod()很重要,我会重新设计UnsetMethod(),如果可以的话,不要扔任何东西。当然,如何做到这一点取决于你正在做什么。

您使用UnsetMethod()SetMethod()失败后进行清理。如果UnsetMethod()无法清理,您可以做些什么?这就是为什么从析构函数中抛出异常是极其危险的原因。

答案 2 :(得分:1)

  1. 不,你通常不能使用你提供的代码。但是,根据您的问题,您可以复制数据,在该副本上执行SetMethod,然后交换表示。这提供了强有力的保证,但又取决于问题。
  2. 您可以记录:如果UnsetMethod没有抛出则有强保证,否则为基本保证。实际上这解释了为什么说析构函数不应该抛出。实际上任何撤消操作都不应该抛出。
  3. 是的,见1。
  4. 不,没有意义。

答案 3 :(得分:0)

从根本上说,在调用throw函数的函数中需要做的是在数据的临时副本上工作,直到所有可能抛出的子函数都完成,然后swap(不能抛出)临时值到'真实'结构。

一些说明性的psudocode:

void MacroMethod() throw(...)
{
  int i = 0;
  MyValues working_copy[100] = *this;  //obviously this is psudocode as I don't know your real code
  for(i = 0; i < 100; ++i)
     working_vopy[i].SetMethod(i); // if this throws the exception will propogate out, and no changes will be made
  swap( *this, working_copy);  // this must not throw
}