异常对象在哪里存储,堆还是栈?如何在不同的类中访问它?

6
最近一位面试官问我,C++中的异常对象是在堆上还是栈上分配的?我不确定,但我回答说它在栈上分配,因为我认为没有“new”或“malloc”。这个回答正确吗?
然后他继续问我,如果它在栈上,假设类A抛出了一个异常对象,比如“e”,而类B捕获了“e”。由于“e”在A的栈上,那么B如何访问这个“e”?
对于第二个问题,我不是很清楚。有人能给我一些示例代码,展示“类A抛出e,类B捕获它”的情况吗?此外,我猜B可以通过复制值或地址来捕获e,但面试官只是否定了我的回答,没有给出正确的答案,那么正确的答案是什么?是否有机制可以确保类对象可以从其他类对象中捕获异常?谢谢~

1
类有它们自己的堆栈?听起来像是一个困惑的面试官。堆栈用于实现函数,整个程序使用同一个;函数抛出异常,函数捕获异常。 - molbdnilo
@molbdnilo - 一个程序可以有多个堆栈。这取决于编译器和所选选项。通常,一个程序在其整个生命周期中使用相同的堆栈,但这并非必需。 - StarPilot
@Deduplicator:回答者们似乎意见不一。能否解释一下? - Silicomancer
1
https://dev59.com/_nI-5IYBdhLWcg3w0cKG - Deduplicator
@Deduplicator 或者两者都可以 :-). 这取决于实现方式。但在实践中,它既不是这样,也很难想象一个使用其中任何一种方式的实现仍然能够正常工作。 - James Kanze
显示剩余2条评论
4个回答

9

来自 [except.throw]/15.1/4:

除了3.7.4.1中提到的情况外,异常对象的内存分配方式未指定。

最终参考文献[basic.stc.dynamic.allocation]/4表示:

[注意]: 特别地,全局分配函数不会被调用来为[...]异常对象 (15.1) 分配存储空间。 — 注释结束]


1
这个注释有点含糊不清(至少没有更多的上下文)。显然,异常不能通过通常的堆栈分配机制进行分配,因此必须调用某种分配函数。(但答案的关键在于第一个引用。在我实际研究过的所有实现中,都使用了自定义分配机制,因此异常既不在堆上也不在栈上。) - James Kanze
@JamesKanze:你说得对,上下文(即这与全局分配函数的定义有关)在这里会有所帮助。 - Kerrek SB
是的。我认为它指的是§3.7中描述的全局分配函数,因为这些函数不能仅用于异常。但是,如果没有上下文,人们很容易理解它指的是任何可全局访问的分配函数。 - James Kanze
clang 调用一个分配异常对象的函数,如果无法分配,则可能返回 nullptr;因此这似乎是一个常规的堆分配。如果该函数返回 nullptr,则 clang 生成的代码调用 std::terminate()。我认为这是分配异常对象的通常方式。 - Bonita Montero

1
无法将其堆栈,因为当异常被抛出时,堆栈会展开,并且如果在导致异常的帧中分配了异常对象,则会丢失该异常对象。我记得在C ++ Primer,第5版中读到过这方面的内容。它说:“异常对象驻留在由编译器管理的空间中,保证对任何调用catch的代码可访问。异常对象在完全处理异常后被销毁。”结合@Kerrek上面的回答,我相信它是分配的单独空间,并且是特定于编译器的。

0
“但我回答了 stack,因为我认为没有“new”或“malloc”。这正确吗?”基本上是的,不过异常处理有点特殊,因为它会展开堆栈以进行 throw 操作。”
 struct SomeException {
 };

 void throwing_func() {
      throw SomeException();
 }

 int main() {
     try {
         throwing_func();
     }
     catch(const SomeException& ex) {
         std::cout << "Caught 'SomeException' exception" << std::endl;
     }
 }

本地作用域

void throwing_func() {
      throw SomeException();
}

这种方法有点类似于查找一个局部作用域,并将该类型的局部作用域与最佳匹配的catch(...)语句进行匹配。


0

抛出新的std::exception vs 抛出std::exception

上面的链接有一个相当不错的答案。

我认为答案会是“通常”是在堆上,因为你抛出的是位于堆上的对象,但如果它是静态对象(不确定这样的东西是否存在),那么它将位于栈上。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接