在c++中可以不调用析构函数就删除一个对象吗?

7gyucuyw  于 2023-06-25  发布在  其他
关注(0)|答案(8)|浏览(149)

我有一个对象,里面有一些指针。析构函数在这些指针上调用delete。但有时我想删除它们,有时我不想。所以我希望能够删除对象而不调用析构函数。这可能吗?
编辑:我意识到这是一个可怕的想法,没有人应该这样做。尽管如此,我还是想这样做,因为它会使一些内部函数更容易编写。

sycxhyv7

sycxhyv71#

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的情况下编写异常安全代码的责任,这是非常困难的。你几乎肯定会弄错。

hm2xizp9

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 999
delete pointer_to_999; // please remember to delete it at the end!
xmq68pz9

xmq68pz93#

恶!是的,有可能,不,我不会这么做的。让需要可变生存期的对象通过共享指针或其他引用计数对象来控制。使用C++比破坏它的一些内部租户更干净。

6ss1mwsb

6ss1mwsb4#

不管你实际上想做什么,你的代码都有问题。如果你不想删除子对象,只需要使用一个布尔标志,你将在删除对象之前设置这个标志,析构函数将考虑这个标志。
但老实说,你应该使用智能指针而不是裸指针(在你的情况下,看起来你需要的是共享指针)。

zhte4eai

zhte4eai5#

编写一个方法,可以在调用析构函数之前调用。该方法将翻转成员布尔值。当destuctor被调用时,它将检查该布尔成员,如果为true,则销毁该指针,如果为false,则保留该指针。
我不建议你这么做。类最好不要负责删除指针。

ehxuflar

ehxuflar6#

是的,这是可能的。std::vector可以做到这一点,因为它为对象分配缓冲区空间,然后有条件地构造它们(就地)并销毁它们,独立于对象生存期管理内存。
在C++11中,我会使用你的类型的union和一个带有普通构造函数/析构函数的小类型来指示一个可以容纳你的类型的内存位置,但不必在其中包含该类型。在外部你必须跟踪物体是否真的在那里。创建项包括使用placement new,销毁项包括手动调用析构函数。
union对象的缓冲区(无论是N个对象还是1个对象)将完全独立地管理。union的默认构造函数要么什么都不构造,要么构造平凡类型(在这种情况下,您可能希望销毁该平凡类型)。
然而,你的问题的真实的答案很可能是“不要那样做”。如果你这样做,你就把指针 Package 在一个class中,它的唯一工作就是处理上面的混乱。这种类型的类(其工作是管理指针的生存期和类似指针的属性)被称为“智能指针”。

fcwjkofz

fcwjkofz7#

正如其他人所建议的,解决这个问题的正确方法不是不调用析构函数[你只需要向对象添加像std::stringstd::vector这样的东西,突然之间你就有了内存泄漏]。正确的方法是要么不让你的对象拥有其他对象(例如:在对象被删除之前/之后分别删除它们),或者具有对象知道是否删除指针的方法。

cbjzeqam

cbjzeqam8#

在c++20中,有一种更好的方法,std::destroying_delete_t标记类型用来标识操作符delete的销毁删除形式。
下面的问题讨论了用法:What is "destroying operator delete" in C++20?

相关问题