内存管理 - 是否可以在不调用析构函数的情况下删除 c++ 中的对象

memory management - Is it possible to delete an object in c++ without calling the destructor?

本文关键字:情况下 析构函数 删除 c++ 对象 调用 管理 是否 内存      更新时间:2023-10-16

我有一个对象,里面有一些指针。 析构函数在这些指针上调用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::stringstd::vector 的东西,突然间您就会出现内存泄漏]。正确的方法是完全不让你的对象拥有这些其他对象(例如,在删除对象之前/之后单独删除它们(,或者有一个对象知道是否删除指针的方法。

在 c++20 中,有一个更好的方法,std::d estroying_delete_t 标签类型用于标识运算符 delete 的销毁删除形式。

下面将讨论用法:什么是 C++20 中的"销毁运算符删除"?

相关文章: