我只是想知道在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
将从其操作数中复制初始化一个新的未命名对象exception object,然后该对象将被catch
块捕获。 Caught在这里意味着catch
块的参数将从异常对象初始化。
[catch
块退出时,其参数会自动销毁,并且如果退出时不重新抛出(并且如果没有std::exception_ptr
引用其左),则异常对象也将被销毁,就像使用当在其中声明它们的块退出时,自动存储持续时间将被破坏;在最终创建完整对象时,临时对象将被破坏。
在您的第一个代码示例中,类型int
的异常对象用值0
初始化,并按值捕获它,这意味着您正在创建类型为int
的新对象作为[ catch
参数,从异常对象初始化。当catch
块退出时,int
参数中的catch
被破坏,并且假设您没有重新抛出,异常对象也将被破坏。
在您的第二个示例中,CString
类型的异常对象是由CString(_T("Hello"))
创建的临时对象初始化的。初始化异常对象后,临时CString(_T("Hello"))
被销毁,因为这是在其中创建完整表达式的结尾。
但是,由于复制省略,因此临时实体永远不会真正实现,并且直接从CString
初始化_T("Hello")
异常对象。 (自C ++ 17开始,这是强制性的,之前已被允许。)
您通过引用捕获异常对象,这意味着将不会创建新副本,并且str
将引用异常对象。当不重新抛出而离开catch
块时,异常对象将再次被自动破坏。
在第三个示例中,您抛出了CString*
,并按值捕获了它,因此适用与示例1中相同的注意事项。当不重新抛出而离开catch
块时,指针lpStr
和也是CString*
的异常对象将被破坏。
但是销毁指针并不意味着该指针所指向的对象已被销毁。 (这就是为什么不应将原始指针用作拥有指针的原因。)
因此,由于指针指向使用new
创建的对象,因此,如果您不希望delete lpStr;
ed new
泄漏,则确实需要通过调用CString
销毁该对象。但是,此delete
不会删除异常对象或catch
参数。 delete
销毁为其指定的指针所指向的对象。 catch
参数是指针lpStr
本身,它是一个自动存储持续时间变量,不能为delete
d。异常对象是另一个指针(具有相同的值),并且未命名,没有任何可能的方式在您的示例中引用它。
您应该像在第二个示例中一样喜欢按引用进行捕获,并且应避免将new
真正用于任何事情。对于具有正确所有权语义的免费商店分配,有智能指针std::unique_ptr
和std::shared_ptr
。