1

I have a fairly large visual studio C++ code base which many people are modifying. There is a requirement to delete an object which possibly many other objects are referring to(using address of raw pointers). I have tried to remove the address references as much as possible, but I am afraid there still might be some that I haven't addressed.

So, I want to know if there is a way to redirect all accesses to the deleted address to a different address, maybe by doing something while deleting so that it would not crash?

petezurich
  • 9,280
  • 9
  • 43
  • 57
user9639921
  • 351
  • 2
  • 11
  • 7
    Please use smart pointers – PapaDiHatti Apr 18 '18 at 05:18
  • Its already very mature code and I cant change the pointer to use smart pointers. That would not be a solution for my case. But thanks for suggesting! – user9639921 Apr 18 '18 at 05:22
  • There is no general solution, hence it is *manual memory management*. Smart pointers is the way, but since you can't use them, you have to painstakingly make sure it's safe to delete. – DeiDei Apr 18 '18 at 05:29
  • 1
    Could you replace all the single pointers with double pointers (`Obj*` to `Obj**`)? If you can't use smart pointers, that's about all I can think of – Justin Apr 18 '18 at 05:33
  • 3
    When instantiating the object, first allocate a suitable block of memory using `VirtualAlloc()` and then construct the object into that memory using `placement-new`. When deleting the object, call its destructor directly instead and dont free the memory, then use `VirtualProtect()` to set the `PAGE_GUARD` modifier on the memory. This way, if the memory is accessed again, a `STATUS_GUARD_PAGE_VIOLATION` exception will be thrown that you can catch with an SEH handler, which allows you to change the address being accessed and then resume execution at the point where the exception occurred. – Remy Lebeau Apr 18 '18 at 06:39

1 Answers1

1

The language does not support what you are trying to do using raw pointers. If you have the option of using std::shared_ptr, you can get what you are looking for.


Response to OP's comment

The objective of using delete is to terminate the life of an object.

If an object is shared by multiple clients, by holding a pointer to the object, independent of one another, you have to make a policy decision on how to manage the life of the object.

  1. Don't allow the life of the object to end until no client has a pointer to it. This is the policy implemented by shared_ptr.

  2. Allow the life of the object to end when the first client wants to end it while making sure that the remaining clients know that the life of the object has ended.

It appears that you want to implement the second policy.

Calling delete directly on the pointer will not work to implement that policy since the language does not support it.

There are no smart pointer classes in the standard library, that I know of, that supports that policy. However, it's not that hard to implement one.

Here's a demonstrative implementation of such a class.

#include <iostream>
#include <cassert>

template <typename T>
struct my_shared_ptr
{
   my_shared_ptr(T* ptr) : dataPtr_(new data(ptr))
   {
   }

   my_shared_ptr(my_shared_ptr const& copy) : dataPtr_(copy.dataPtr_)
   {
      ++(dataPtr_->use_count_);
   }

   ~my_shared_ptr()
   {
      delete dataPtr_->ptr_;

      --(dataPtr_->use_count_);
      if ( dataPtr_->use_count_ == 0 )
      {
         delete dataPtr_;
      }
      else
      {
         dataPtr_->ptr_ = nullptr;
      }
   }

   // Overloaded operator functions to use objects of
   // the class as pointers.
   T& operator*()
   {
      assert(dataPtr_->ptr_ != nullptr);
      return *(dataPtr_->ptr_);
   }

   const T& operator*() const
   {
      assert(dataPtr_->ptr_ != nullptr);
      return *(dataPtr_->ptr_);
   }

   T* operator->()
   {
      assert(dataPtr_->ptr_ != nullptr);
      return dataPtr_->ptr_;
   }

   const T* operator->() const
   {
      assert(dataPtr_->ptr_ != nullptr);
      return dataPtr_->ptr_;
   }

   struct data
   {
      data(T* ptr) : ptr_(ptr), use_count_(1) {}
      T* ptr_;
      size_t use_count_;
   };

   data* dataPtr_;
};

int main()
{
   my_shared_ptr<int> ptr1{new int(10)};

   std::cout << *ptr1 << std::endl;

   my_shared_ptr<int> ptr2{ptr1};

   std::cout << *ptr2 << std::endl;

   {
      my_shared_ptr<int> ptr3{ptr1};
      std::cout << *ptr3 << std::endl;
   }

   // Problem. The int got deleted when ptr3's life ended 
   // in the above block.
   std::cout << *ptr1 << std::endl;

   return 1;
}

Output of the above program built with g++:

10
10
10
socc: socc.cc:35: T& my_shared_ptr<T>::operator*() [with T = int]: Assertion `dataPtr_->ptr_ != nullptr' failed.
Aborted

Please note that you will need to implement at least the copy assignment operator to make the class confirm to The Rule of Three. You will need further improvements to deal with pointers to base classes and derived classes.

R Sahu
  • 204,454
  • 14
  • 159
  • 270
  • But won't even a shared_ptr become dangling in case the object is deleted? – user2672165 Apr 18 '18 at 06:29
  • 1
    @user2672165 no, the object *isn't deleted* until there are no `shared_ptr`s pointing to it – Caleth Apr 18 '18 at 08:52
  • @Caleth The question is about " delete an object which possibly many other objects are referring to". I simply don't understand how std::shared_ptr solves that. – user2672165 Apr 22 '18 at 18:53
  • @user2672165 `shared_ptr` tracks how many instances point to the object. When the last `shared_ptr` destructor runs, *it* `delete`s the object – Caleth Apr 22 '18 at 19:31