C ++中“finally”的异常策略

时间:2013-12-22 17:17:39

标签: c++ exception-handling raii finally

考虑类finally,在析构函数中运行任意用户代码。

这是最小的实现(没有转发,辅助功能等):

template<typename Func>
class finally
{
public:
    finally(Func f) : f_(f) {}
    ~finally() { f_(); }

private:
    Func f_;
};

问题是:应该如何处理用户代码中的异常?

以下是我能想到的变体,假设该类应该在各种情况下使用,你认为它们中的哪一个更好?

1)什么都不做。 ~finally() /*noexcept*/ { f_(); }

finally的析构函数隐式noexcept,因此用户代码中的任何异常都会导致terminate()。 用户必须每次都想到他的代码没有被忽略,并且如果它抛出则用try / catch手动保护它。

2)完全透明的析构函数。 ~finally() noexcept(f_()) { f_(); }

finally的析构函数有条件地noexcept,因此任何异常都会被传递,只有在堆栈展开期间发生terminate()时才会调用它。 用户应该考虑堆栈展开场景,但在这种情况下调用terminate()可能是默认的正确决定。

3)在析构函数中捕获所有异常。 ~finally() { try { f_(); } catch (...) {} }

经典析构函数不抛任何东西。 限制用户使用异常进行错误检查的能力,但具有良好的意图。由于try / catch块可能效率较低。用户无需考虑任何事情。

3 +)(可能)优化3),如果f_()noexcept,则使用specialization / SFINAE省略try / catch块。

可以在try / catch块中冗余地包含像fclose(FILE*)这样的C函数,因为它们不是noexcept,但是这些函数可能不会直接用于最终,而是通过lambdas,它也很容易不被标记为{{ 1}}出于健忘。

4)静态断言noexcept是noexcept。

用户每次都必须明确地将他的代码标记为f_(),然后捕获或不捕获异常是他关注的问题。再次限制用户使用异常进行错误检查的能力,但具有良好的意图。

4 +) 4)加上一些特殊化的finally(甚至是另一个单独的类模板),其语义为2),没有断言,但必须明确使用。

0 个答案:

没有答案