我有3个问题:
1。总是说通过引用捕获异常对象。在下面的示例中,我看到在执行 catch 块之前调用了析构函数,这意味着我们引用了 catch 中的一个对象,该对象必须超出范围。我们使用它的时间。为什么要使用参考呢?
class MyException{
public:
~MyException() {
cout<<"Dtor for MyException called \n";
}
};
int main()
{
try{
MyException obj1;
throw obj1;
}
catch(MyException& obj)
{
cout<<"Catched unhandled exception";
}
2. 为什么析构函数在这里被调用两次?在进入 catch 块之前,在执行 catch 之后第二次完成。
3. Lifetime of a thrown object caught by reference中的示例显示析构函数只被调用一次,即在 catch 块退出后,只有复制构造函数< / em>在类中定义。
a。当我们通过引用来捕捉它时,复制构造函数的作用是什么?
b。即使在定义了复制构造函数之后,它也永远不会被调用。那它会产生什么影响?
c。我试图在我的例子中定义一个拷贝构造函数,如下所示,但我仍然看到析构函数被调用两次。为什么?:
MyException(const MyException& obj)
{
}
有人可以回答所有5个问题(第3个问题有3个部分)。
答案 0 :(得分:2)
您正在将您创建的例外副本作为本地临时文件抛出。所以有两个:第一个在你抛出时被销毁,第二个(副本)在catch块完成后被销毁。
试试这个:
try { throw MyException{}; }
catch (MyException const& obj) { }
编辑:如果您的代码中没有调用您的复制构造函数,那么我的猜测是编译器已经识别出异常类为空?编译器可以自由地执行它选择的任何优化,只要代码的行为是 - 如果它没有。对此的例外是copy-ellision,但如果发生这种情况,你就不会得到双析构函数。
答案 1 :(得分:2)
throw
总是复制你正在投掷的物体。您不能抛出不可复制的对象。事实上,如果throw
无法为副本分配足够的内存,try
甚至会失败。obj1
- 块内调用析构函数。它是您本地obj1
的析构函数。一旦你扔掉它的副本,它就会超出范围。throw
的析构函数。当你扔掉它的副本时它会超出范围。答案 2 :(得分:1)
他们建议您通过引用获取catch块以避免切片(因为继承异常是标准的)并避免不必要的复制,因为throw
无条件地复制。
您无法通过引用收到obj1
,因为throw obj1
会导致它被销毁(因为它不再在范围内)。由于此throw
始终复制到您无法控制的临时内存位置。
obj1
以及我之前提到过的临时文件。 obj
是对该临时值的引用,引用的临时值将在catch块结束后和下一个操作之前被销毁(类似于它实际上是catch块的本地)。
单个析构函数仅在复制被删除且标准不能保证何时发生时才会发生,因为复制省略总是可选的。定义复制构造函数没有区别,因为如果您没有定义它(并且可以创建它),编译器会为您定义它。删除复制构造函数只会导致throw
非法。
一个。如上所述,复制构造函数复制到临时。参考参考说临时。
湾你真的删除了复制构造函数吗? MyException(const MyException&) = delete;
是如何删除复制构造函数,未能定义它只是让编译器为您创建一个。重复一遍,删除它会导致throw
非法。
℃。因为副本没有被删除,并且存在两个对象,一个临时文件和你的对象。