通过引用捕获(使用 catch)时异常对象的范围
Scope of Exception object when caught(using catch) by reference
我有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. 通过引用捕获的抛出对象的生存期中的示例表明,析构函数只被调用一次,即只有在类中定义了复制构造函数时,catch 块退出后。
a. 当我们通过引用捕获复制构造函数时,它的作用是什么?
b. 即使在定义了复制构造函数之后,它也不会被调用。那么它会产生什么影响呢?
c. 我也尝试在我的示例中定义一个复制构造函数,如下所示,但我仍然看到析构函数被调用了两次。为什么?:
MyException(const MyException& obj)
{
}
有人可以回答所有 5 个问题(第 3 个问题有 3 个部分(。
您正在抛出您作为本地临时创建的异常的副本。 所以有两个:第一个在你投掷时被摧毁,第二个(副本(在捕获块完成后被销毁。
试试这个:
try { throw MyException{}; }
catch (MyException const& obj) { }
编辑:如果你的复制构造函数真的没有在你的代码中被调用,那么我的猜测是编译器已经认识到异常类是空的? 编译器可以自由地执行它选择的任何优化,只要代码的行为是 - 就好像它没有一样。 例外是复制,但如果发生这种情况,您将不会得到双重析构函数调用。
-
throw
总是复制你扔的物体。您不能抛出不可复制的对象。事实上,如果throw
无法为副本分配足够的内存,它甚至可能会失败。
这应该解释为什么你看到一个析构函数在try
块中被调用。它是您本地obj1
的析构函数。一旦你扔出它的副本,它就会超出范围。
至于通过引用捕获,它用于避免不必要的复制,更重要的是,潜在的切片。 - 再一次,它是您当地
obj1
的破坏者.当你扔掉它的副本时,它超出了范围。 - a( 如果通过引用捕获,则不执行复制。仅当您按值捕获时,才会执行复制(具有潜在的切片(。
b( 你错了,throw
调用一个复制构造函数来制作你的对象的副本并抛出它。不会调用复制构造函数的唯一情况是抛出临时对象并且编译器会忽略副本。
c( 参考我的第一个和第二个答案。
他们建议您通过引用来获取 catch 块以避免切片(因为继承异常是标准的(并避免不必要的复制,因为throw
无条件复制。
-
您无法通过引用接收
obj1
throw obj1
因为这会导致它被销毁(因为它不再在范围内(。因此,throw
始终复制到您无法控制的临时内存位置。 -
obj1
和我之前提到的临时。obj
是对该临时的引用,则引用的临时将在 catch 块结束后和下一个操作之前销毁(类似于如果它实际上是 catch 块的本地(。 -
单个析构函数仅在省略副本时发生,标准不保证何时会发生,因为复制省略始终是可选的。定义复制构造函数没有区别,因为如果您不定义它(并且可以创建它(,编译器会为您定义它。删除复制构造函数只会导致
throw
是非法的。-
一个。如上所述,复制构造函数以复制到临时构造函数中。参考参考说是暂时的。
-
二.你是否真的删除了复制构造函数?
MyException(const MyException&) = delete;
是你删除复制构造函数的方式,不定义它只会导致编译器为你创建一个。再说一遍,删除它会导致throw
是非法的。 -
三.由于未省略副本,并且存在两个对象,一个是临时对象,一个是你的对象。
-
- 关于:C++中异常对象的范围:为什么我没有得到副本?
- 创建具有 new in 函数和"this is nullptr"异常的对象
- 对象初始化后在C++中显示 char 数组时的异常行为
- 如何捕获 C++ 内置异常对象
- 异常对象的最后一个潜在销毁点
- 异常表达式创建的异常对象的类型
- 异常对象的静态类型
- 抛出非异常对象
- 异常对象寿命
- 关于异常对象的双重销毁需要解释
- 异常对象在哪里有其空间、堆或堆栈,以及如何在不同的类中访问它
- 如果引发的异常始终是异常对象的副本,为什么不调用此复制构造函数?
- 通过引用捕获(使用 catch)时异常对象的范围
- 存储在异常对象中的信息:在异常中提供字符串
- 当一个异常对象被销毁时(它可以被控制吗)
- 如果我跳出带有"goto"的捕获块,我能保证异常对象将被释放吗?
- 通过引用抛出异常对象是否合适?
- 可以rethrow_exception真正抛出相同的异常对象,而不是副本
- c++能消除异常对象类型的歧义吗?
- 作为抛出异常对象的结构基类