异常对象的空间、堆或堆栈在哪里,以及如何在不同的类中访问它? 最近,一个采访者问我 C++中的异常对象是分配的,堆还是堆栈?< /强>我不确定,但是我回答了堆栈,因为我认为没有“新”或“Malc”。对吗

异常对象的空间、堆或堆栈在哪里,以及如何在不同的类中访问它? 最近,一个采访者问我 C++中的异常对象是分配的,堆还是堆栈?< /强>我不确定,但是我回答了堆栈,因为我认为没有“新”或“Malc”。对吗,c++,exception,memory,heap-memory,stack-memory,C++,Exception,Memory,Heap Memory,Stack Memory,然后他一直问我如果它在堆栈上,假设类A抛出一个异常对象,比如说“e”,而类B捕获“e”。既然“e”在A的堆栈上,那么B如何访问该“e”? 第二个问题我不太清楚。谁能给我一些示例代码,说明“类A抛出e,类B捕获它”?另外,我猜B可以通过复制值或地址来捕捉e,但面试官只是拒绝了我的答案,而没有给出正确的答案,那么正确的答案是什么呢?是否有任何机制可以确保类对象可以捕捉到来自其他类对象的异常?感谢~来自[except.throw]/15.1/4: 异常对象的内存以未指定的方式分配,3.7.4.1中说明

然后他一直问我如果它在堆栈上,假设类A抛出一个异常对象,比如说“e”,而类B捕获“e”。既然“e”在A的堆栈上,那么B如何访问该“e”?


第二个问题我不太清楚。谁能给我一些示例代码,说明“类A抛出e,类B捕获它”?另外,我猜B可以通过复制值或地址来捕捉e,但面试官只是拒绝了我的答案,而没有给出正确的答案,那么正确的答案是什么呢?是否有任何机制可以确保类对象可以捕捉到来自其他类对象的异常?感谢~

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

异常对象的内存以未指定的方式分配,3.7.4.1中说明的除外

最后一个参考[basic.stc.dynamic.allocation]/4说:

[注意:特别是,不会调用全局分配函数为[…]异常对象(15.1)分配存储。-结束注意]

“但是我回答了堆栈,因为我认为没有“新”或“malloc”。对吗?”

基本上是的,尽管异常处理有点特殊,因为它展开
抛出操作的堆栈

 struct SomeException {
 };

 void throwing_func() {
      throw SomeException();
 }

 int main() {
     try {
         throwing_func();
     }
     catch(const SomeException& ex) {
         std::cout << "Caught 'SomeException' exception" << std::endl;
     }
 }
在某种程度上等同于查找一个
本地范围
,并将这种
本地范围
与最佳匹配的
catch(…)
语句相匹配。

上面的链接有一个很好的答案


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

它不能是堆栈,因为抛出异常时堆栈会展开,如果在导致异常的帧中分配了异常对象,则会丢失异常对象

我记得在C++入门书中读到过一些关于它的内容。上面说

exception对象驻留在由编译器管理的空间中,保证调用任何catch都可以访问该空间。异常被完全处理后,异常对象被销毁


再看看上面@Kerrek的asnwer,我相信它是一个单独分配的空间,专门针对编译器。

有自己堆栈的类?这听起来像是一个困惑的面试官。堆栈用于实现函数,整个程序使用相同的堆栈;函数抛出异常,函数捕获异常。@molbdnilo-一个程序可以有多个堆栈。这取决于所选的编译器和选项。通常,一个程序在其整个生命周期中使用相同的堆栈,但这不是必需的。答案是两者都不是。@重复数据消除:回答者似乎不同意。想解释一下吗?注释有点模棱两可(至少没有更多的上下文)。显然,通常的堆栈分配机制无法分配异常,因此必须调用某种类型的分配函数。(但答案的关键在第一句话中。在我实际研究的实现中,所有的实现都使用自定义分配机制,因此异常既不在堆上也不在堆栈上。)@JamesKanze:你是对的,上下文(即这与全局分配函数的定义有关)在这里会有所帮助。是的。我认为它指的是§3.7中所述的全局分配功能,因为这些功能不能用于例外情况,至少不能仅用于例外情况。但是在上下文之外,我们很容易理解它是指任何全局可访问的分配函数。clang调用一个分配异常对象的函数,如果无法分配异常对象,该函数可能返回nullptr;因此,这似乎是一种常见的堆分配。如果函数返回nullptr,则clang生成的代码将调用std::terminate()。我认为这是分配异常对象的通常方式。
void throwing_func() {
      throw SomeException();
}