Reputation: 6366
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.
Upvotes: 14
Views: 10693
Reputation: 21
In c++20, there is a better way,std::destroying_delete_t tag type used to identify the destroying delete form of operator delete.
Usage is discussed in this question below: What is "destroying operator delete" in C++20?
Upvotes: 1
Reputation: 88155
The delete
operator does two things to the object you pass it:
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.
Upvotes: 14
Reputation: 275385
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".
Upvotes: 2
Reputation: 1199
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.
Upvotes: 2
Reputation: 28241
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!
Upvotes: 7
Reputation: 129344
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.
Upvotes: 1
Reputation: 15069
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).
Upvotes: 2
Reputation: 12515
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...
Upvotes: 3