为什么C++异常(可能)被复制

Why are C++ exceptions (potentially) copied

本文关键字:复制 可能 C++ 异常 为什么      更新时间:2023-10-16

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

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

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

根据对我的问题的评论,我认为这或多或少地回答了它(尽管我的措辞可能不准确(:

为什么允许复制异常

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

throw my_exception("This is wrong!);

而不是像那样抛出指针

throw new my_exception("This is wrong!);

当异常由值引发时,它会被分配到堆栈上,并且由于堆栈将被展开,因此必须复制才能将其传播到堆栈上。

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

问题并不像看上去那么大

正如formerlykknownas_463035818所指出的,大多数程序员不应该担心在复制另一个异常时出现内存不足异常(bad_alloc(。如果内存太满,以至于没有空间容纳异常的副本,那么程序几乎肯定很快就会崩溃。

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