是否可以在不调用析构函数的情况下删除c ++中的对象?

时间:2013-02-14 18:02:29

标签: c++ memory-management destructor

我有一个对象,里面有一些指针。析构函数在这些指针上调用delete。但有时我想删除它们,有时我不删除它们。所以我希望能够在没有调用析构函数的情况下删除对象。这可能吗?

编辑:我意识到这是一个绝对的想法,任何人都不应该这样做。尽管如此,我想这样做是因为它会使一些内部函数更容易编写。

7 个答案:

答案 0 :(得分:8)

您可以将指针设置为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!

答案 1 :(得分:8)

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的异常安全代码的责任,这非常困难。你几乎可以保证弄错了。

答案 2 :(得分:4)

好恶!是的,这是可能的,不,我不会这样做。通过共享指针或其他一些引用计数对象来控制需要变量生命周期的对象。使用C ++更清洁而不是打破一些内部租户...

答案 3 :(得分:2)

无论您真正尝试做什么,您的代码都会出现问题。 如果您不想删除子对象,只需使用在删除对象之前设置的布尔标志,并且析构函数将考虑该标志。

但老实说,你应该使用智能指针而不是裸指针(在你的情况下,它看起来像你需要的共享指针)。

答案 4 :(得分:2)

编写一个可以在调用析构函数之前调用的方法。该方法将翻转成员布尔值。当调用destuctor时,它将检查该布尔成员并在指针为真时销毁指针,如果指针为假则保留该指针。

我不建议这样做。最好让班级不负责删除指针。

答案 5 :(得分:1)

正如其他人所建议的那样,解决这个问题的正确方法不是不要调用析构函数[你只需要在你的对象中添加std::stringstd::vector这样的东西,并且所有这些都是突然你有内存泄漏]。正确的方法是不要让你的对象完全拥有那些其他对象(例如,在删除对象之前/之后单独删除它们),或者有一个方法用于知道是否删除指针。

答案 6 :(得分:1)

是的,这是可能的。 std::vector这样做,因为它为对象分配缓冲区,然后有条件地构造它们(就地)并销毁它们,独立于对象生命周期管理内存。

在C ++ 11中,我使用你的类型的union和一个带有普通构造函数/析构函数的小类型来指示一个适合你的类型的内存位置,但不一定要有输入它。在外部,您必须跟踪对象是否实际存在。创建项目包括使用展示位置new,并且销毁它包括手动调用析构函数。

union个对象的缓冲区,无论是N个对象还是1个,都将完全独立地进行管理。 union的默认构造函数可以不构造任何内容,也可以构造普通类型(在这种情况下,您可能希望销毁那种简单的类型)。

但是,很可能你的问题的真正答案是“不要那样做”。如果你这样做,你将指针包装在class中,其作业处理上述混乱。该类型的类(其作用是管理指针的生命周期和类指针属性)称为“智能指针”。