Reputation: 129
If in theory imagine a situation where, by chance or by mistake (either through carelessness, or due to lack of experience, etc.), the memory was freed twice using delete-exprssion (yes, a good developer will not allow this, in well-designed architectural solutions, but howewer) how to (can we, or is there any method to) safty handle the situation so that the application does not crash?
Upvotes: 0
Views: 401
Reputation: 3372
You can take ownership of memory management for a given type by overriding the new
and delete
operators. This is not straightforward (for example overriding for array allocation) and Scott Meyers Effective C++ books has some great material on this (Item 16 for example), but I believe in theory it would give you the ability to delete a pointer twice.
I am not sure what the standard's view on this would be so I suspect as many have already said about this area of the language, deleting the same object twice would still be Undefined Behaviour.
Still, for the sake of discussion...
#include <iostream>
#include <unordered_set>
namespace {
class DeleteMeTwice
{
static std::unordered_set<void *> deleted;
public:
void * operator new (std::size_t count)
{
void * const result = ::operator new(count);
std::cout << "Newing: " << result << "\n";
return result;
}
void operator delete(void *ptr)
{
if (is_deleted(ptr))
{
std::cout << "Not deleting: " << ptr << "\n";
}
else
{
std::cout << "Deleting: " << ptr << "\n";
::operator delete(ptr);
deleted.insert(ptr);
}
}
static bool is_deleted(void *ptr)
{
return deleted.find(ptr) != deleted.end();
}
};
std::unordered_set<void *> DeleteMeTwice::deleted;
}
int main(int argc, char **argv)
{
DeleteMeTwice * const ptwice = new DeleteMeTwice;
delete ptwice;
delete ptwice;
return 0;
}
Running on OSX with c++ Apple LLVM version 10.0.0 (clang-1000.11.45.5)
returns:
Newing: 0x7fc384c02ab0
Deleting: 0x7fc384c02ab0
Not deleting: 0x7fc384c02ab0
Upvotes: 0
Reputation: 234795
The behaviour of delete p; delete p;
is undefined unless p
is nullptr
.
Setting the deleted pointer to nullptr
following the delete
is one way: the C++ standard requires delete p;
and delete[] p;
to be a no-op if p
is nullptr
. In other words delete p; p = nullptr; delete p; p = nullptr;
is well-defined.
But this can lead to untidy code.
Other than the facetious advice to take more care, using smart pointer classes such as std::unique_ptr
and std::shared_ptr
eliminates the need for explicit delete
s.
Upvotes: 6
Reputation: 76438
The way to do it is to provide your own versions of operator new
and operator delete
. operator new
gets memory by calling malloc()
, and operator delete()
releases it by calling free()
. That's pretty much what the standard library ones do. But yours can do more. operator new()
gets the memory, then adds the address that it got to a list of allocated addresses. operator delete()
first checks whether the pointer that was passed to it is in the list of allocated addresses. If so, it removes it from the list and frees the memory. If not, it throws an exception.
You won't like the performance.
Upvotes: 1
Reputation: 56527
Smart pointers were invented to deal with this problem.
If an object X
is owned by object Y
then Y
should have std::unique_ptr<X>
instead of raw pointer. No delete needed, X
will be cleaned when Y
is destroyed (or it decides to release the pointer).
If an object X
is shared between some objects then each of them should have copies of std::shred_ptr<X>
. Again no delete needed.
The only thing you should think about is: who owns what and when?
EDIT: (to satisfy literal question) No, you can't do anything about it. Double delete is UB. The sixth circle of hell. Although you can try to catch segfault (which is often caused by double delete) this will only increase your torment because you are in an undefined space anyway. The only way to handle it safely is to get rid of it.
Upvotes: 8
Reputation: 129
I fount the answer! To that question the only answer is: No. It is undefined behavior.
Upvotes: -1
Reputation: 5261
There are situations where you may need to new
and delete
. "Just use smart pointers" can be a cop out in practice. Especially with legacy software. If you must delete
an object, it's better to set it null afterwards, (and null check before deleting.)
someObject *myptr = new someObject;
..... elsewhere in code to free .....
if (myptr) {
delete myptr;
myptr = nullptr;
}
This ensures the object underlying the pointer is only deleted once.
Upvotes: 2
Reputation: 36503
so that the application does not crash
This is just a side-effect, an implementation detail of the real problem. Double deleting causes undefined behavior according to the standard.
There is no way to turn a program exhibiting undefined behavior back into one defined so no, there is no way to handle it safely.
Ideally you shouldn't be using new
or delete
at all.
Upvotes: 6
Reputation: 181380
No. You can't do that. What you could do (as a good practice is):
char *some_pointer = new char[100];
// use the pointer
strcpy(some_pointer, "this is it");
printf("%s", some_pointer);
// ALWAYS NULL the POINTER after DELETE
delete(some_pointer);
some_pointer = NULL;
So, whenever you are about to allocate memory for a pointer you could double check:
if (some_pointer != NULL) {
// allocate
} else {
// THIS IS SOME KIND OF BUG, can't continue
}
Upvotes: 0