我需要手动销毁抛出的物体吗?
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
本身,一个自动存储时长变量,不能delete
d。异常对象是另一个指针(具有相同的值)并且未命名,无法在您的示例中引用它。
您应该像第二个示例中那样更喜欢按引用捕获,并且您应该避免对任何真正的东西使用 new
。有智能指针 std::unique_ptr
和 std::shared_ptr
用于免费存储分配,具有正确的所有权语义。
我只是想知道在 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
本身,一个自动存储时长变量,不能delete
d。异常对象是另一个指针(具有相同的值)并且未命名,无法在您的示例中引用它。
您应该像第二个示例中那样更喜欢按引用捕获,并且您应该避免对任何真正的东西使用 new
。有智能指针 std::unique_ptr
和 std::shared_ptr
用于免费存储分配,具有正确的所有权语义。