James
James

Reputation: 129

Is there any method to safe handle twice freeing memory by delete-expression?

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

Answers (8)

WaffleSouffle
WaffleSouffle

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

Bathsheba
Bathsheba

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 deletes.

Upvotes: 6

Pete Becker
Pete Becker

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

freakish
freakish

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

James
James

Reputation: 129

I fount the answer! To that question the only answer is: No. It is undefined behavior.

Upvotes: -1

Cinder Biscuits
Cinder Biscuits

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

Hatted Rooster
Hatted Rooster

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

Pablo Santa Cruz
Pablo Santa Cruz

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

Related Questions