如何正确处理构造函数中的异常?

时间:2012-10-04 09:12:20

标签: c++ exception-handling constructor

  

可能重复:
  How to clean initialized resources if exception thrown from constructor in c++

如果我创建6个对象并且这些对象创建5个对象并且在创建第6个对象时失败,我如何处理构造函数中的异常?

感谢。

3 个答案:

答案 0 :(得分:3)

通常的行为就是让异常传播。析构函数 对于任何完全构造的基类,将调用成员; 如果前五个对象是成员,它们将是正确的 遭到破坏。

可能出现问题的唯一情况是您是否是对象 谈论已被动态分配(使用new)。如果那样的话 案例:首先要问自己是为什么?你为什么 动态分配,而不是使对象成为具体成员?在 根据我的经验,这种需求是非常非常罕见的,除了一些特殊的 案例(例如编译防火墙成语),在这种情况下,会有 通常只是类中的一个对象(例如指向 实施对象)。在这种情况下,没有问题,因为如果 该对象的new失败,没有其他任何需要做的事情 撤销。

如果你发现自己处于极为罕见的情况下,你真的 必须使用动态分配有多个这样的对象 (例如,因为你有两个多态的子对象),那么 你必须确保每个分配都包含在一些中 一种子对象(一个智能指针可以做到这一点);一旦第一次 子对象已经成功构建,它的析构函数将是 如果构造函数稍后失败则调用。

答案 1 :(得分:1)

当构造函数中抛出异常时,所有完全构造的子对象都将被销毁。由于优良做法是使构造对象的析构函数照顾它们的resoyrces,因此不需要为这些子对象做任何事情。剩下的是在抛出异常时清理当前正在执行的构造函数的主体。但是,这与任何其他功能的清理没有什么不同。

请注意,销毁订单与构造相反。也就是说,当所有子对象尚未被破坏时,身体的清理首先开始。然后销毁成员,然后销毁非虚拟基类,最后是虚拟基类。

答案 2 :(得分:1)

处理异常的“核心”是几乎所有东西都应该通过析构函数来清理。例如,如果你“新”一个对象,你会得到一个“原始”指针;如果在某处抛出异常,则必须确保此原始指针正确地“删除”d - 但请确保不删除尚未初始化的原始指针。

另一方面,如果将指针存储到std :: unique_ptr中,则无需执行任何操作;当unique_ptr被销毁时,对象被删除,并且对象破坏自动发生:当unique_ptr超出范围时,编译器调用清理,完全不可见(因此没有更多的代码混乱,大量的清理调用)和自动(所以没有更多'哎哟,当它需要一条罕见的路径,没有人真正测试它忘记清理')。

同样可以应用于几乎所有资源; COM对象有“自动指针”(例如在DirectX中使用),大多数框架应该为你提供一个“scoped lock”类型的对象来包装互斥锁(因此它在创建对象时锁定互斥锁,并且当它被破坏时解锁它,你可以编写小包装来处理各种Windows句柄。

基本上,如果你把所有的清理工作都放到析构函数中,你就永远不必“尝试......抓住...重新抛出”只是为了清理。 “较大”对象的析构函数通常非常简单,因为几乎所有“包含”的对象都被它们的析构函数自动清理。