Home > OS >  Heap corruption on deleting a pointer twice stored in different classes
Heap corruption on deleting a pointer twice stored in different classes

Time:07-07

Two classes A and B share pointer to a third class C and when either A or B are deleted they call delete C as well.

Issue is not observed when only either of A or B is deleted. An exception is getting thrown in this scenario. I have specifically tried to set the class C pointer to NULL and have put in a NULL check to avoid this specific scenario but this null check is somehow not working.

I have read around that shared pointer should be used in this case but I am not sure how to implement it properly. It looks like whole code base needs to be changed to include shared_ptr everywhere as all class C objects would be updated to shared_ptr. Is there a way I can use shared_ptr just to store this pointer without changing all the code?

Edit: I have specifically deleted assignment operator and copy constructor of C to avoid situation both have different pointers due to copying. Can anything else can be done to prevent copying as pointed in answer by john

class A{
  C* c;
}
~A(){
  if(C != NULL){
  delete C;
  C = NULL;
 }
}

class B{
 C* c;
}

~B(){
  if(C != NULL){
  delete C;
  C = NULL;
 }
}

CodePudding user response:

A and B have separate copies of the pointer to C. So setting one classes copy of that pointer to NULL has no effect on the other pointer and you still get a double delete.

You have basically four options

  1. Decide that one class 'owns' the pointer, that class will delete it and the other will not. The danger here is that if the owning class deletes the pointer and then the non-owning class uses the pointer then you are going to get a different kind of error.

  2. Use shared ownership of the pointer, so that it only gets deleted when the last object using it gets destroyed. The easy way to do that is to use std::shared_ptr

    #include <memory>
    
    class A {
        std::shared_ptr<C> c;
    };
    
    class B {
        std::shared_ptr<C> c;
    };
    
  1. Clone the pointer before copying it to the second class. Something roughly like

     a.c = new C();
     b.c = new C(*a.c);
    

this way both classes get separate (but equal) copies of the C object. But this changes the semantics of your program, maybe you actually want A and B to share the same C object.

  1. This option (suggested by Richard Critten) has class A having a std::shared_ptr and class B having a std::weak_ptr. This means that A owns the C object, and when the last A object has been destroyed the C object will also be destroyed. Any remaining B objects do not prevent the destruction of the C object but, the B object can check whether the C object has been destroyed. In code it looks something like this

    #include <memory>
    
    class A
    {
        std::shared_ptr<C> c;
    };
    
    class B
    {
        std::weak_ptr<C> c;
    };
    
    class C
    {
         C(whatever);
    };
    
    A a;
    B b;
    // create a shared pointer
    a.c = std::make_shared<C>(whatever);
    // create a weak pointer referring to the same C object
    b.c = a.c;
    
    // create a shared pointer from the weak pointer in b
    auto c = b.c.lock();
    // check if the pointer is valid
    if (c)
    {
         // do something with c
         c->something();
    }
    else
    {
         // c object has been destroyed
    }
    
  • Related