【问题标题】:Should private function members be exception safe?私有函数成员应该是异常安全的吗?
【发布时间】:2020-07-20 18:14:10
【问题描述】:

在编写异常安全代码时,所有私有成员函数都应该至少保证基本的异常安全吗?在这种情况下,最佳/最佳做法是什么?替代品?

例如,假设我有一个类Foopublic 函数成员DoSomething,它调用private 函数成员DoSomeOfItDoSomeOfIt 可能由于某些我无法影响的功能而失败,并且当它发生时,它可能会使 Foo 对象处于部分修改状态,这违反了 Foo 的不变量。所以我可以将DoSomeOfIt 包装在try-catch 块中,并在catch 块中调用另一个private 函数成员UndoThat 来撤消DoSomeOfIt 所做的事情。单独来说,DoSomeOfItUndoThat 可能不是异常安全的,但 DoSomething 是。那会是异常安全代码吗? (本案有强保证)

class Foo {
public:
  // I provide strong exception safety guarantee
  void DoSomething() {
    try {
      DoSomeOfIt();
    } catch (const std::exception& e) {
      UndoThat();
      throw;
    }
  }
private:
  // I provide no exception safety guarantee.
  DoSomeOfIt() {
    // may throw and violate class invariants.
  }

  // I provide no exception safety guarantee.
  UndoThat() {
    // undoes everything most recent call of
    // DoSomeOfIt did.
  }
};

当然,我可以简单地将DoSomeOfItUndoThat 的代码包含在DoSomething 中,但这可能会导致代码膨胀和函数体过长,而分解函数会使任务模块化,并可能使代码更具可读性(?)

免责声明: 我知道这可能是基于意见的。我不确定这是否会成为一篇糟糕的帖子,但我会很感激任何意见或经验,这会导致问题,或者是常见的做法等。

【问题讨论】:

  • 基于意见 - 这是实施的细节;用户Foo 只关心它的公共(和受保护)接口。只要公共合同(包括例外保证)得到履行,私有实现就可以做它喜欢的任何事情。
  • 每当我用 C++ 编写 catch 时,我都会想知道 RAII 是否会更好。通常,(并非总是),我发现 RAII 更好。由于您暗示UndoThat() 可以抛出异常,这可能是RAII 不是最佳答案的情况,但我想我会为后续读者发表评论。 void DoSomething() {StateSave saveState; DoSomeOfIt(); saveState.setSucceeded();}

标签: c++ private-members private-methods exception-safety


【解决方案1】:

这是我的看法。

如果DoSomeOfIt 有可能被多个函数使用,则最好将异常处理代码驻留在该函数本身中——您不想拥有异常处理代码跨多个功能重复。如果这不可能,您发布的代码就可以了。

话虽如此,如果将异常处理代码移至DoSomething,则不会丢失任何内容。事实上,功能变得更好。如果将来被另一个函数使用,异常处理已经处理好了。从那个角度来看,把异常处理代码移到DoSomething会比较好。

【讨论】:

  • 我可以看到这样做的好处。但是,UndoThat 也有同样的问题。但我想按照这个逻辑,UndoThat 只会被DoSomeOfIt 调用,所以不会有问题。
  • 我个人会更严格地说DoSomeOfIt 应该始终处理异常处理。不知道下一个维护者将来如何使用它,并且假设所有类不变量始终得到维护是一个更容易的心理模型
  • @Human-Compiler 当然,整个事情都是基于意见的,但我想说这是始终支持所有类不变量的更简单的心理模型与可能的代码膨胀之间的权衡。 DoSomeOfIt 可能是一个调用其他函数的复杂函数,而DoSomething 可能不仅仅是DoSomeOfIt,可能还有类似的问题。最终,我想知道权衡是否会倾向于模块化。
猜你喜欢
  • 2020-09-18
  • 2012-03-01
  • 1970-01-01
  • 2012-03-10
  • 2020-03-22
  • 2010-10-13
  • 1970-01-01
  • 2011-01-18
  • 2018-04-04
相关资源
最近更新 更多