我有一个对象,里面有一些指针。析构函数在这些指针上调用delete。但有时我想删除它们,有时我不想。所以我希望能够删除对象而不调用析构函数。这可能吗?编辑:我意识到这是一个可怕的想法,没有人应该这样做。尽管如此,我还是想这样做,因为它会使一些内部函数更容易编写。
delete
sycxhyv71#
delete操作符对传递给它的对象做两件事:
operator delete
所以删除一个对象而不调用析构函数意味着你只需要在对象上调用operator delete:
Foo *f = new Foo;operator delete(f);
Foo *f = new Foo;
operator delete(f);
operator delete是一个普通的函数调用,并完成了通常的名称查找和重载解析。然而,delete运算符有自己的规则来找到正确的operator delete。例如,delete运算符将查找通常的名称查找和重载解析找不到的成员operator delete函数。这意味着您需要确保在手动使用operator delete时调用正确的函数。正如你所说,直接使用operator delete是一个糟糕的想法。调用析构函数失败会破坏RAII,导致资源泄漏。它甚至可能导致未定义的行为。此外,你还必须承担在没有RAII的情况下编写异常安全代码的责任,这是非常困难的。你几乎肯定会弄错。
hm2xizp92#
你可以将指针设置为NULL,那么析构函数就不会删除它们。
struct WithPointers{ int* ptr1; int* ptr2; WithPointers(): ptr1(NULL), ptr2(NULL) {} ~WithPointers() { delete ptr1; delete ptr2; }}...WithPointers* object1 = new WithPointers;WithPointers* object2 = new WithPointers;object1->ptr1 = new int(11);object1->ptr2 = new int(12);object2->ptr1 = new int(999);object2->ptr2 = new int(22);...int* pointer_to_999 = object2->ptr1;object2->ptr1 = NULL;delete object1;delete object2; // the number 999 is not deleted now!// Work with the number 999delete pointer_to_999; // please remember to delete it at the end!
struct WithPointers
{
int* ptr1;
int* ptr2;
WithPointers(): ptr1(NULL), ptr2(NULL) {}
~WithPointers()
delete ptr1;
delete ptr2;
}
...
WithPointers* object1 = new WithPointers;
WithPointers* object2 = new WithPointers;
object1->ptr1 = new int(11);
object1->ptr2 = new int(12);
object2->ptr1 = new int(999);
object2->ptr2 = new int(22);
int* pointer_to_999 = object2->ptr1;
object2->ptr1 = NULL;
delete object1;
delete object2; // the number 999 is not deleted now!
// Work with the number 999
delete pointer_to_999; // please remember to delete it at the end!
xmq68pz93#
恶!是的,有可能,不,我不会这么做的。让需要可变生存期的对象通过共享指针或其他引用计数对象来控制。使用C++比破坏它的一些内部租户更干净。
6ss1mwsb4#
不管你实际上想做什么,你的代码都有问题。如果你不想删除子对象,只需要使用一个布尔标志,你将在删除对象之前设置这个标志,析构函数将考虑这个标志。但老实说,你应该使用智能指针而不是裸指针(在你的情况下,看起来你需要的是共享指针)。
zhte4eai5#
编写一个方法,可以在调用析构函数之前调用。该方法将翻转成员布尔值。当destuctor被调用时,它将检查该布尔成员,如果为true,则销毁该指针,如果为false,则保留该指针。我不建议你这么做。类最好不要负责删除指针。
ehxuflar6#
是的,这是可能的。std::vector可以做到这一点,因为它为对象分配缓冲区空间,然后有条件地构造它们(就地)并销毁它们,独立于对象生存期管理内存。在C++11中,我会使用你的类型的union和一个带有普通构造函数/析构函数的小类型来指示一个可以容纳你的类型的内存位置,但不必在其中包含该类型。在外部你必须跟踪物体是否真的在那里。创建项包括使用placement new,销毁项包括手动调用析构函数。union对象的缓冲区(无论是N个对象还是1个对象)将完全独立地管理。union的默认构造函数要么什么都不构造,要么构造平凡类型(在这种情况下,您可能希望销毁该平凡类型)。然而,你的问题的真实的答案很可能是“不要那样做”。如果你这样做,你就把指针 Package 在一个class中,它的唯一工作就是处理上面的混乱。这种类型的类(其工作是管理指针的生存期和类似指针的属性)被称为“智能指针”。
std::vector
union
new
class
fcwjkofz7#
正如其他人所建议的,解决这个问题的正确方法不是不调用析构函数[你只需要向对象添加像std::string或std::vector这样的东西,突然之间你就有了内存泄漏]。正确的方法是要么不让你的对象拥有其他对象(例如:在对象被删除之前/之后分别删除它们),或者具有对象知道是否删除指针的方法。
std::string
cbjzeqam8#
在c++20中,有一种更好的方法,std::destroying_delete_t标记类型用来标识操作符delete的销毁删除形式。下面的问题讨论了用法:What is "destroying operator delete" in C++20?
8条答案
按热度按时间sycxhyv71#
delete
操作符对传递给它的对象做两件事:operator delete
。所以删除一个对象而不调用析构函数意味着你只需要在对象上调用
operator delete
:operator delete
是一个普通的函数调用,并完成了通常的名称查找和重载解析。然而,delete
运算符有自己的规则来找到正确的operator delete
。例如,delete
运算符将查找通常的名称查找和重载解析找不到的成员operator delete
函数。这意味着您需要确保在手动使用operator delete
时调用正确的函数。正如你所说,直接使用
operator delete
是一个糟糕的想法。调用析构函数失败会破坏RAII,导致资源泄漏。它甚至可能导致未定义的行为。此外,你还必须承担在没有RAII的情况下编写异常安全代码的责任,这是非常困难的。你几乎肯定会弄错。hm2xizp92#
你可以将指针设置为NULL,那么析构函数就不会删除它们。
xmq68pz93#
恶!是的,有可能,不,我不会这么做的。让需要可变生存期的对象通过共享指针或其他引用计数对象来控制。使用C++比破坏它的一些内部租户更干净。
6ss1mwsb4#
不管你实际上想做什么,你的代码都有问题。如果你不想删除子对象,只需要使用一个布尔标志,你将在删除对象之前设置这个标志,析构函数将考虑这个标志。
但老实说,你应该使用智能指针而不是裸指针(在你的情况下,看起来你需要的是共享指针)。
zhte4eai5#
编写一个方法,可以在调用析构函数之前调用。该方法将翻转成员布尔值。当destuctor被调用时,它将检查该布尔成员,如果为true,则销毁该指针,如果为false,则保留该指针。
我不建议你这么做。类最好不要负责删除指针。
ehxuflar6#
是的,这是可能的。
std::vector
可以做到这一点,因为它为对象分配缓冲区空间,然后有条件地构造它们(就地)并销毁它们,独立于对象生存期管理内存。在C++11中,我会使用你的类型的
union
和一个带有普通构造函数/析构函数的小类型来指示一个可以容纳你的类型的内存位置,但不必在其中包含该类型。在外部你必须跟踪物体是否真的在那里。创建项包括使用placementnew
,销毁项包括手动调用析构函数。union
对象的缓冲区(无论是N个对象还是1个对象)将完全独立地管理。union
的默认构造函数要么什么都不构造,要么构造平凡类型(在这种情况下,您可能希望销毁该平凡类型)。然而,你的问题的真实的答案很可能是“不要那样做”。如果你这样做,你就把指针 Package 在一个
class
中,它的唯一工作就是处理上面的混乱。这种类型的类(其工作是管理指针的生存期和类似指针的属性)被称为“智能指针”。fcwjkofz7#
正如其他人所建议的,解决这个问题的正确方法不是不调用析构函数[你只需要向对象添加像
std::string
或std::vector
这样的东西,突然之间你就有了内存泄漏]。正确的方法是要么不让你的对象拥有其他对象(例如:在对象被删除之前/之后分别删除它们),或者具有对象知道是否删除指针的方法。cbjzeqam8#
在c++20中,有一种更好的方法,std::destroying_delete_t标记类型用来标识操作符delete的销毁删除形式。
下面的问题讨论了用法:What is "destroying operator delete" in C++20?