【发布时间】:2021-05-08 08:48:51
【问题描述】:
我看到了这篇文章:Best practice: throw by value, catch by const reference,并对异常对象何时被破坏感到好奇。
这是我的异常结构,就像文章中的第二个示例一样(带有一些 std::cout 的)。
struct BASE_EX {
static int id;
BASE_EX() {
++id;
std::cout << "constructing BASE_EX " << id << std::endl;
}
virtual std::string const what() const { return "BASE_EX " + std::to_string(id); }
~BASE_EX() { std::cout << "destructing BASE_EX " << id << std::endl; }
};
struct DERIVED_EX : BASE_EX {
static int derived_id;
DERIVED_EX() {
++derived_id;
std::cout << "constructing DERIVED_EX " << derived_id << std::endl;
}
std::string const what() const { return "DERIVED_EX " + std::to_string(derived_id); }
~DERIVED_EX() { std::cout << "destructing DERIVED_EX " << derived_id << std::endl; }
};
int BASE_EX::id = 0;
int DERIVED_EX::derived_id = 0;
运行这个主函数时,通过 const& 捕捉:
int main() {
try {
try {
throw DERIVED_EX();
} catch(BASE_EX const& ex) {
std::cout << "First catch block: " << ex.what() << std::endl;
throw ex;
}
} catch(BASE_EX const& ex) {
std::cout << "Second catch block: " << ex.what() << std::endl;
}
}
我明白了
constructing BASE_EX 1
constructing DERIVED_EX 1
First catch block: DERIVED_EX 1
destructing DERIVED_EX 1
destructing BASE_EX 1
Second catch block: BASE_EX 1
destructing BASE_EX 1
问题一:如果BASE_EX在第二次catch之前就被破坏了,它是如何被捕捉到的?
问题 2:为什么破坏比构建多?
问题3:当我将两个catch都改为catch by value而不是const&时,为什么输出变成了
constructing BASE_EX 1
constructing DERIVED_EX 1
First catch block: BASE_EX 1
destructing BASE_EX 1
destructing DERIVED_EX 1
destructing BASE_EX 1
Second catch block: BASE_EX 1
destructing BASE_EX 1
destructing BASE_EX 1
任何关于 cpp try-catch 如何在后台工作的推荐读物都会很棒。谢谢。
【问题讨论】:
-
该异常在概念上在它通过的每个块的末尾被破坏,并传递一个副本。然而,编译器可能(并且在实践中,为了效率通常会这样做)省略一些 - 但重要的是,不一定是所有 - 副本。如果异常最终被捕获,则它在相关捕获处理程序的末尾不再存在。如果未捕获到异常,则程序以调用
std:abort()结束,而不必调用析构函数。如果您跟踪复制(或移动?)构造函数的调用,您可能会更好地了解正在发生的事情。 -
“如果 [object] 在 [X] 之前被破坏,那么它 [still around] 是怎么回事?” -- 这种形式的问题经常出现在人们试图跟踪建设和破坏,但忽略Rule of Three。让我们看看......是的,就是这样。
-
谢谢@Peter 和 JaMiT。我认为 JaMiT 共享的两个链接回答了我的问题。
标签: c++ exception destructor