我需要手动销毁抛出的物体吗?

Need I Destroy a Thrown Object Manually?

我只是想知道在 C++ 中是否需要我手动销毁抛出的对象?

在下面的代码中,如何销毁抛出的0?

try
{
   ...
   throw 0;
}
catch(int i)
{
   // How to destroy the thrown 0?
}

在下面的代码中,如何销毁抛出的CString对象?

try
{
   ...
   throw CString(_T("Hello"));
}
catch(CString& str)
{
   // How to destroy the thrown str?
}

在下面的代码中,我可以销毁抛出的对象,因为它是作为 CString*

从堆中分配的
try
{
   ...
   throw new CString(_T("Hello"));
}
catch(CString* lpStr)
{
   delete lpStr;
}

您不需要也不允许手动销毁异常对象或 catch 参数。

throw 将从其操作数复制初始化一个新的未命名对象,即 异常对象 ,然后该对象被 catch 块捕获. Caught这里的意思是catch块的参数会从异常对象中初始化

catch 块退出时,它的参数会自动销毁,如果它退出而不重新抛出(如果没有 std::exception_ptr 引用它),异常对象也将被销毁,与具有自动存储持续时间的对象在声明它们的块退出时销毁或临时对象在创建它们的完整表达式结束时销毁的方式相同。

在您的第一个代码示例中,类型 int 的异常对象被初始化为值 0 并且您按值捕获它,这意味着您正在创建类型的新对象 int作为catch参数中的变量,从异常对象中初始化。当 catch 块退出时 catch 参数中的 int 被销毁,假设您没有重新抛出,异常对象也被销毁。

在您的第二个示例中,CString 类型的异常对象是从 CString(_T("Hello")) 创建的临时对象初始化的。临时 CString(_T("Hello")) 在异常对象初始化后被销毁,因为这是创建它的完整表达式的结尾。

由于复制省略,临时对象永远不会真正实现,CString 异常对象直接从 _T("Hello") 初始化。 (这是强制性的,因为 C++17 之前是允许的。)

您通过引用捕获异常对象,这意味着不会创建新副本并且 str 将引用异常对象。 当离开 catch 块而不重新抛出时,异常对象将再次自动销毁。

在第三个示例中,您抛出一个 CString* 并按值捕获它,因此适用与示例 1 中相同的注意事项。当离开 catch 块而不重新抛出时,指针 lpStr 和异常对象,也是一个 CString*,将被销毁。

销毁指针并不意味着销毁指针指向的对象。 (这就是为什么不应将原始指针用作拥有指针的原因。)

因此,由于指针指向使用 new 创建的对象,如果您不想要 new,您确实需要通过调用 delete lpStr; 来销毁该对象ed CString 泄漏。但是,此 delete 不会删除异常对象或 catch 参数 delete 销毁给它的指针指向的对象。 catch参数是指针lpStr本身,一个自动存储时长变量,不能deleted。异常对象是另一个指针(具有相同的值)并且未命名,无法在您的示例中引用它。

您应该像第二个示例中那样更喜欢按引用捕获,并且您应该避免对任何真正的东西使用 new。有智能指针 std::unique_ptrstd::shared_ptr 用于免费存储分配,具有正确的所有权语义。