需要我手动销毁一个被投掷的物体吗?

问题描述 投票:0回答:1

我只是想知道在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;
}
c++ exception try-catch throw
1个回答
4
投票

您不需要并且不允许手动销毁异常对象或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_ptrstd::shared_ptr

© www.soinside.com 2019 - 2024. All rights reserved.