11

I have an object with some pointers inside of it. The destructor calls delete on these pointers. But sometimes I want to delete them, and sometimes I don't. So I'd like to be able to delete the object without calling the destructor. Is this possible?

Edit: I realize this is an AWFUL idea that no one should ever do. Nonetheless, I want to do it because it will make some internal functions much easier to write.

4

7 に答える 7

12

The delete operator does two things to the object you pass it:

  • calls the appropriate destructor.
  • calls the deallocation function, operator delete.

So deleting an object without calling a destructor means you want to simply call operator delete on the object:

Foo *f = new Foo;
operator delete(f);

operator delete is a normal function call and the usual name lookup and overload resolution is done. However the delete operator has its own rules for finding the correct operator delete. For example the delete operator will look for member operator delete functions that the usual name lookup and overload resolution does not find. That means that you need to make sure you're calling the right function when you manually use operator delete.

As you say, using operator delete directly is an awful idea. Failing to call the destructor breaks RAII, resulting in resource leaks. It can even lead to undefined behavior. Also, you'll have to take on the responsibility of writing exception safe code without RAII, which is exceptionally hard. You're almost guaranteed to get it wrong.

于 2013-02-14T19:03:46.557 に答える
7

You can set the pointers to NULL, then the destructor will not delete them.

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!
于 2013-02-14T18:12:10.207 に答える
4

Eww! Yes, it's possible, no I wouldn't do it. Have the objects that need variable lifetime be controlled via a shared pointer or some other reference counted object instead. Cleaner to work with C++ than breaking some of its internal tenants...

于 2013-02-14T18:05:39.320 に答える
2

Whatever you're actually trying to do, there is a problem with your code. If you don't want to delete the sub-objects, just use a boolean flag that you will set before deleting the object and that will be taken into account by the destructor.

But honestly, you should be using smart pointers instead of naked pointers (and in your very case, it looks like shared pointers are what you need).

于 2013-02-14T18:08:19.543 に答える
2

Write a method that you can call before calling the destructor. The method will flip a member boolean. When the destuctor is called, it will check that boolean member and destroy the pointer if it is true, and keep it if it is false.

I wouldn't recommend doing this. Better for the class to not take responsibility for deleting the pointer.

于 2013-02-14T18:13:10.297 に答える
2

Yes, this is possible. std::vector does this, in that it allocates buffers with space for objects, then conditionally constructs them (in-place) and destroys them, managing the memory independently of the object lifetime.

In C++11, I'd use a union of your type and a small type with trivial constructors/destructors to indicate a memory location that can fit your type, but doesn't have to have that type in it. External to that you have to track if the object is actually there. Creating the item consists of using placement new, and destroying it consists of manually calling the destructor.

The buffer of the union objects, be it N objects or 1, would be managed completely independently. The default constructor of the union would either construct nothing, or construct the trivial type (in which case you might want to destroy that trivial type).

However, odds are that the real answer to your question is "don't do that". And if you do that, you wrap the pointers in a class whose only job is handling the above mess. Classes of that type (whose job is to manage a pointer's lifetime and pointer-like properties) are called "smart pointers".

于 2013-02-14T18:15:39.457 に答える
1

As others have suggested, the correct way to solve this problem isn't to NOT call the destructor [you only need to add something like std::string or std::vector to your object, and all of a sudden you have a memory leak]. The correct way is to either not let your object own those other objects at all (e.g. delete them separately before/after the object is deleted), or have a method with which the object knows whether to delete the pointers or not.

于 2013-02-14T18:11:59.957 に答える