【问题标题】:Noexcept promise on derived class constructor: can that be used without promising noexcept on base constructor?派生类构造函数上的 Noexcept 承诺:可以在不承诺基础构造函数上的 noexcept 的情况下使用它吗?
【发布时间】:2016-08-10 19:40:21
【问题描述】:

假设我有一堂课

class C : public B {
  public:
    C() noexcept;
}

noexcept 说明符是否需要基类的相同承诺?也就是说,我在考虑使用noexcept的时候,是只看C::C()的行为还是还需要考虑B::B()是否会抛出异常?

例如,如果 B::B 抛出异常,它会传播到 C::C 还是传播到请求新类实例的代码? -- 如果传播到 C::C,如果基类不是构造函数的 noexcept,那将是避免构造函数的 noexcept 的原因之一。

【问题讨论】:

  • 基类构造失败,派生类构造能否成功?
  • 没有。那么,当编译器将这一切放在一起时,它是否独立处理每个构造函数,这意味着派生类上的 noexcept 规范对编译器如何管理基构造函数没有影响?
  • 实际上,我认为我的问题可能具有误导性。如果您的基类是 vector 并且您将其传递给零大小,您实际上可以保证不会抛出异常。同样,noexcept 表示不能抛出某些东西,以免调用abort()(我认为,请参阅文档)。因此,如果基础构造函数还不是noexcept,则必须将其包裹在try - catch 中,但它可以满足noexcept 保证。
  • 我想问我问题的更好方法是:异常接下来会去哪里?如果基类构造函数抛出异常,是转到派生类构造函数还是调用该构造函数的代码?
  • @UlrichEckhardt 如果基类构造函数抛出异常,派生类构造函数实际上不可能“吞下”该异常:派生构造函数必须抛出或程序必须终止。

标签: c++ c++11 exception


【解决方案1】:

从技术上讲不需要将基类构造函数声明为 noexcept,但它不能在被声明为 noexcept 的派生构造函数调用时抛出。

所以是的,您确实需要考虑基类构造函数是否可能抛出(异常或其他)。

我想问我问题的更好方法是:异常接下来会去哪里?

调用流程如下:

caller
  -> derived constructor (the noexcept applies to this)
    -> subobject constructors (includes bases)
    - derived constructor body (not a call, but part of the derived constructor that is executed after the subobjects are constructed)

因此,如果子对象(无论是基类还是成员)构造函数抛出,它首先会转到派生构造函数,它不会也不能†† 吞下异常,所以如果构造函数不是 noexcept,它将传播给调用者。但既然是这样,std::terminate 就会被调用。

如果基数确实没有按照派生的要求抛出,那么它确实满足要求并且本身可以声明为 noexcept,因此很少有理由不这样做。也许,如果基类是必须支持 c++03 的库的一部分,而派生类可能会采用更高版本的标准,那将是有意义的。

††它可以用函数try-block捕获,但那些总是会再次抛出。

【讨论】:

  • 你可以在C的ctor上使用一个function-try-block来产生一个很好的错误信息(虽然它必须继续中止程序,没有办法恢复)
  • @M.M 哦,是的,我忘了这些。我在答案中添加了注释。
猜你喜欢
  • 2016-06-17
  • 1970-01-01
  • 2021-09-14
  • 2022-12-03
  • 1970-01-01
  • 2015-10-15
  • 1970-01-01
  • 2015-11-03
  • 2019-03-07
相关资源
最近更新 更多