【问题标题】:Why are C++ exceptions (potentially) copied为什么 C++ 异常(可能)被复制
【发布时间】:2019-11-20 13:11:30
【问题描述】:

this answerthis 之类的页面,我了解到异常可能在被抛出的过程中被复制。我还了解到,这个复制不能抛出任何额外的异常,否则会调用std::terminate()。这使得编写异常类变得困难,因为例如std::string 在复制时可能会引发异常。

我的问题:为什么 C++ 允许编译器复制异常?通过引用或指针抛出它们并要求程序员通过引用或指针而不是值来捕获它们会有什么缺点?

似乎一个解决方案可能是将任何重要的成员包装在std::shared_ptr 之类的东西中,并复制该指针而不是它持有的对象。但随后我们失去了复制的所有潜在优势(例如,您可以在原件保持不变的情况下编辑副本)。那么为什么 C++ 坚持要能够复制异常呢?

【问题讨论】:

  • 您链接的答案没有提及复制异常。它谈到了在构造异常时复制std::string
  • 一般来说,你不能禁止别人复制你抛出的异常。你的问题基本上是问为什么标准是这样的,恕我直言太宽泛/基于意见
  • 顺便说一句,内存不足是您很少能从中恢复的。如果你不是在做一些超级关键的事情,我不会太担心创建一个抛出第二个异常的异常
  • 你知道std::current_exception吗?如果没有,检查它的作用,并思考必须发生的事情,应该可以回答您的问题。
  • @BiagioFesta - 在这里,通过复制或引用来捕捉不是重要的。即使你捕获了一个引用,current_exception 也需要复制当前的异常对象,以便构造它的exception_ptr,因为异常对象通常是在自动范围内构造的。始终在动态范围内构造异常对象消除了可复制异常的需要,但增加了 99% 的时间不需要的大量开销。因此,在自动范围内构造,并仅在绝对需要时复制异常对象。

标签: c++ exception copy-constructor


【解决方案1】:

根据我的问题的 cmets,我认为这或多或少地回答了它(尽管我的措辞可能在这里和那里不准确):

为什么允许复制例外

大多数异常都是按值抛出的,即

throw my_exception("This is wrong!);

而不是像扔指针一样

throw new my_exception("This is wrong!);

当一个异常被值抛出时,它被分配到堆栈上,并且由于堆栈将被展开,它必须被复制以便将它传播到堆栈上。

因此,如果标准不要求异常可复制,则必须要求将所有异常作为指向堆分配对象的指针抛出。但正如 Sam Varshavchik 指出的那样,这会增加一些通常不需要的开销。异常通常是小对象,因此与在堆上分配和释放它们相比,复制它们可能会产生更少的开销。

问题并不像看起来那么大

正如之前所知的_463035818 所指出的,在复制另一个异常时遇到内存不足异常 (bad_alloc) 并不是大多数程序员应该担心的事情。如果内存已满以至于没有空间存放异常的副本,那么程序几乎肯定很快就会崩溃。

但是,以这样一种方式编写异常很重要,即它们的复制构造函数不会抛出各种其他异常,因为这会终止程序,而它可能已经能够捕获原始异常并从中恢复它。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-25
    • 1970-01-01
    • 1970-01-01
    • 2017-09-16
    • 1970-01-01
    • 2014-08-12
    相关资源
    最近更新 更多