内存管理 - 是否可以在不调用析构函数的情况下删除 c++ 中的对象
memory management - Is it possible to delete an object in c++ without calling the destructor?
我有一个对象,里面有一些指针。 析构函数在这些指针上调用delete
。 但有时我想删除它们,有时我不想。 所以我希望能够在不调用析构函数的情况下删除对象。 这可能吗?
编辑:我意识到这是一个可怕的想法,没有人应该这样做。 尽管如此,我想这样做,因为它会使一些内部函数更容易编写。
delete
运算符对你传递给它的对象执行两项操作:
- 调用相应的析构函数。
- 调用释放函数,
operator delete
。
因此,删除对象而不调用析构函数意味着您只需对对象调用operator delete
:
Foo *f = new Foo;
operator delete(f);
operator delete
是正常的函数调用,通常的名称查找和重载解析已完成。但是,delete
运算符有自己的规则来查找正确的operator delete
。例如,delete
运算符将查找通常的名称查找和重载解析找不到的成员operator delete
函数。这意味着您需要确保在手动使用 operator delete
时调用正确的函数。
正如你所说,直接使用operator delete
是一个糟糕的主意。未能调用析构函数会中断 RAII,从而导致资源泄漏。它甚至可能导致未定义的行为。此外,您必须承担在没有 RAII 的情况下编写异常安全代码的责任,这非常困难。你几乎肯定会弄错。
您可以将指针设置为 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 999
delete pointer_to_999; // please remember to delete it at the end!
哇! 是的,这是可能的,不,我不会这样做。 改为通过共享指针或其他一些引用计数对象来控制需要可变生存期的对象。 与C++合作比破坏一些内部租户更干净......
无论你实际想做什么,你的代码都有问题。如果不想删除子对象,只需使用在删除对象之前设置的布尔标志,析构函数将考虑该标志。
但老实说,你应该使用智能指针而不是裸指针(在你的情况下,看起来共享指针是你需要的(。
编写一个可以在调用析构函数之前调用的方法。该方法将翻转成员布尔值。当调用 destuctor 时,它将检查该布尔成员并销毁指针(如果为真(,如果为假则保留指针。
我不建议这样做。最好让类不负责删除指针。
是的,这是可能的。 std::vector
这样做,因为它为对象分配缓冲区空间,然后有条件地构造它们(就地(并销毁它们,独立于对象生存期管理内存。
在 C++11 中,我会使用你的类型的union
和一个带有简单构造函数/析构函数的小类型来指示一个适合你的类型的内存位置,但不必包含该类型。 除此之外,您必须跟踪对象是否实际存在。 创建项包括使用放置new
,销毁它包括手动调用析构函数。
union
个对象的缓冲区(无论是 N 个对象还是 1 个对象(都将完全独立管理。 union
的默认构造函数要么不构造任何内容,要么构造普通类型(在这种情况下,您可能希望销毁该简单类型(。
但是,您的问题的真正答案很可能是"不要那样做"。 如果你这样做,你就把指针包装在一个class
中,它唯一的工作就是处理上面的混乱。 这种类型的类(其工作是管理指针的生存期和类似指针的属性(称为"智能指针"。
正如其他人所建议的那样,解决此问题的正确方法不是不调用析构函数[您只需要向对象添加类似 std::string
或 std::vector
的东西,突然间您就会出现内存泄漏]。正确的方法是完全不让你的对象拥有这些其他对象(例如,在删除对象之前/之后单独删除它们(,或者有一个对象知道是否删除指针的方法。
在 c++20 中,有一个更好的方法,std::d estroying_delete_t 标签类型用于标识运算符 delete 的销毁删除形式。
下面将讨论用法:什么是 C++20 中的"销毁运算符删除"?
- 在这种情况下显式调用时,std::cout 如何更改析构函数的行为?
- 在这种情况下,工会成员会调用自己的析构函数吗
- C++ 在不释放内存的情况下调用析构函数
- 在特殊情况下使析构函数不是虚拟的,并删除基指针是否安全
- 在scoped_ptr发生异常的情况下未调用析构函数
- 在这种情况下,我的派生类是否还需要一个虚拟析构函数
- 为什么std::vector::template在没有调用任何复制构造函数的情况下调用析构函数
- 为什么标准允许我在没有析构函数的情况下自由存储分配类
- 在不先显式调用析构函数的情况下,在旧对象上使用placement new是否危险
- 在不使用虚拟析构函数的情况下删除继承的对象时中止
- 在非虚拟析构函数的情况下自动调用父析构函数
- 是否可以使用 std::shared_ptr 创建共享对象池,并在没有自定义析构函数的情况下创建weak_ptr
- 如何在不调用现有对象的析构函数的情况下在向量中添加和初始化对象
- 在这种情况下,我是否需要调用矢量的析构函数
- 如何在不中断移动和复制构造函数的情况下声明虚拟析构函数
- 是否可以在不知道类型的情况下调用析构函数
- 如果在没有限定的情况下从构造函数/析构函数调用虚拟函数,则是否会发生虚拟调度
- 是否可以在不调用包含对象的析构函数的情况下清空映射的内容?
- 在不调用析构函数的情况下结束STL容器的生存期
- 在虚拟析构函数的情况下,虚拟机制是如何工作的