【问题标题】:Constructor as a function try block - Exception aborts program构造函数作为函数尝试块 - 异常中止程序
【发布时间】:2015-03-11 08:33:03
【问题描述】:

我不确定这是编译器的问题还是我做错了什么。我正在使用 Visual Studio 2013 编译器。

我有一个类,我需要在我的构造函数初始化器列表中获取大量资源,其中大部分资源都可能引发异常。我将成员初始值设定项列表包装在一个函数 try 块中,并在那里捕获了异常。但是即使 catch 子句没有重新抛出异常,我的程序仍然会中止。我不允许发布实际代码。所以我用这个等效的演示代码重现了这个问题。有人可以帮我解决这个问题吗?

#include <iostream>
using namespace std;
class A{
public:
    A() try : i{ 0 }{ throw 5; }
    catch (...){ cout << "Exception" << endl; }
private:
    int i;
};


int main(){
    A obj;
}

在执行此代码时,我收到一个 Windows 警报“abort() 已被调用”。所以我猜系统将其视为未捕获的异常并调用终止()。

另一方面,如果我将 main() 中对象的构造包装在 try-catch 块中,则异常被正确捕获,程序正常终止。

如果我在这里做错了什么,有人可以告诉我吗?

【问题讨论】:

  • 查看gotw.ca/gotw/066.htm 了解有关此问题的讨论
  • 非常感谢 Jan Herrmann。对于标准来说,如果没有重新抛出异常或者没有从构造函数的函数 try 块中抛出新的异常,那么它将在 catch 块的末尾自动重新抛出,这显然是很有意义的。现在这很有意义。也许正如建议的 pimpl idiom 是我应该开始使用的。再次非常感谢
  • 加分“我不允许发布实际代码。所以我已经用这个等效的演示代码重现了这个问题。” 你做了一个非常好的MCVE。
  • 很好的问题。
  • 如果所有的问题都这样写,水晶球的市场将一落千丈。

标签: c++ c++11


【解决方案1】:

有一个相关的gotw

http://gotw.ca/gotw/066.htm

基本上即使你不抛出你的catch块,异常也会自动重新抛出

如果处理程序主体包含语句“throw;”然后抓住 块显然会重新抛出任何异常 A::A() 或 B::B() 发出。不太明显但在标准中明确说明的是 如果 catch 块没有抛出(要么重新抛出原来的 异常,或抛出新的东西),并且控制到达结束 catch 构造函数或析构函数的块,然后是原始的 异常会自动重新抛出。

【讨论】:

  • 那页读起来真的很棒。在这个问题之前不知道 function-try-block 语法存在;从那个链接学到了很多!特别是,有一个奇妙的类比:“如果任何基础或成员对象的构造失败,整个对象必须失败......如果其中任何一个是重要器官,人类就无法[出生]从未形成”。
  • 整个 gotw 网站对于任何 C++ 开发人员来说都是一座金矿!连同 Bjarne 的网站、parashift、cppreference 和 cplusplus
  • 自从我发表上述评论以来,我在 48 分钟内就发现了这一点!最近的遗憾是 2008 年 1 月 1 日。
【解决方案2】:

根据the cppreference.com documentation for function-try blocks,这是正常行为:构造函数或析构函数上的所谓 function-try-block 必须从其 catch 子句中抛出,否则在捕获子句。

这很有意义:对象A 没有正确构造,因此不处于适合使用的状态:它必须抛出异常。您必须确保在构造对象的地方构造是否成功,即在main() 中的示例中。

【讨论】:

  • 赞成,因为这个答案比引用的标准答案更具人类可读性。对于 OP:您的问题是您的一个或多个成员处于未构造状态(由于您不知道哪个成员的构造抛出,您不知道哪些成员已完全构造)。因此,您的课程尚未完全构建。让它重新抛出可确保您无法使用此实例。完全构造的成员将被适当地破坏。
【解决方案3】:

无法在构造函数function-try-block 中捕获异常。

n3376 15.2/15

如果控制到达结束,则重新抛出当前处理的异常 构造函数或析构函数的函数尝试块的处理程序。

你应该在对象创建的地方捕获它。

【讨论】:

    【解决方案4】:

    我建议你阅读网站上的文章:“GotW #66 Constructor Failures”:http://gotw.ca/gotw/066.htm

    【讨论】:

      猜你喜欢
      • 2013-11-10
      • 2011-04-22
      • 2016-04-09
      • 1970-01-01
      • 2014-05-27
      • 1970-01-01
      • 2015-08-10
      • 2012-04-14
      • 1970-01-01
      相关资源
      最近更新 更多