Reinterpret cast for pointer of pointer

91 Views Asked by At

I have two classes: a Parent class and a Child class (inheriting from the Parent class). I would like to know if it is possible to cast/transform a Child** to a Parent** with reinterpret_cast or something else. Is such a thing possible?

Below is a minimal example. I am wondering is that code correct, or Child** to a Parent** "transformation" is not correct and should not be attempted?

NB: my question is on the conversion of the pointer of pointer, i.e., is this line correct?

Parent** ptrToChildPtr = reinterpret_cast<Parent**>(&childPtr);

I know that the pointer deletion could be done in a much simpler way. I just want to show here the conversion I want to perform, if such conversion is possible.

Many thanks in advance.

#include <iostream>
#include <memory>

class Parent {
public:
    Parent() {}
    virtual ~Parent() {
        std::cout << "Destructor of Parent class" << std::endl;
    }
};

class Child : public Parent {
public:
    Child() {}
    virtual ~Child() {
        std::cout << "Destructor of Child class" << std::endl;
    }
};

void deletePointer(Parent** ptr) {
  if (*ptr) {
    delete *ptr;
    *ptr = nullptr;
  }
}

int main() {
  Child* childPtr = new Child();
  Parent** ptrToChildPtr = reinterpret_cast<Parent**>(&childPtr);

  std::cout << "Before delete function: childPtr = " << childPtr << std::endl;
  deletePointer(ptrToChildPtr);
  std::cout << "After delete function: childPtr = " << childPtr << std::endl;

  return 0;
}

Edit (suggested)

Maybe providing a more concrete example as to why I would like to transform some pointers because the answers I got are not really answering the core of the issue

I have a code (not coded by me and I cannot change its structure it is too big) where basically a lot of raw pointers of different types Child1, Child2, ... ChildN inheriting from Parent class are initialized (so using new... and thus should be deleted with delete)

At different moments in the code I would need to delete those pointers and initialize either all of them or few of them again. Which is painful to track so I would like to have a PointerHandler class that takes care of initializing and deleting those pointers calling respectively the initPointer() and deleteAllPointers function (as shown below) but so for that I would need to store the addess of pointers holders within the PointerHandler class hence the question about transforming addresses

#include <iostream>
#include <vector>
#include <string>
#include <memory>

class Parent {
public:
    Parent(const std::string & name): m_name(name) {}
    virtual ~Parent()  {
        std::cout << "Deleter of Parent class name=" << m_name << std::endl;
    }
    protected: 
      std::string m_name;
};

class Child1 : public Parent {
  public:
    Child1(const std::string & name): Parent(name) {}
    virtual ~Child1() {
        std::cout << "Deleter of Child1 class for name=" << m_name << std::endl;
    }
};

class Child2 : public Parent {
  public:
    Child2(const std::string & name): Parent(name) {}
    virtual ~Child2() {
        std::cout << "Deleter of Child2 class for name=" << m_name << std::endl;
    }
};


class PointerHandler{
  public: 
    PointerHandler(){}
    ~PointerHandler(){ deleteAllPointers(); }

    // Template function to init the pointers
    template<class TChildClass> 
    void initPointer(const std::string &name, TChildClass * &childPtr){
      // Init the child pointer 
      childPtr = new TChildClass(name);

      // Keep track of the pointer adress so that it can be deleted 
      Parent** ptrToChildPtr = reinterpret_cast<Parent**>(&childPtr);
      m_vecPtrs.push_back(ptrToChildPtr);
    }

    void deleteAllPointers(){
      // Delete all pointers and reset pointer holder to nullptr 
      for (Parent **ptr: m_vecPtrs){
        deleterFunction(ptr);
      }
      m_vecPtrs.clear();
    }

  private: 
    std::vector<Parent**> m_vecPtrs;
    // Function used to delete pointers
    void deleterFunction(Parent** ptr) {
      if (*ptr){
        delete *ptr;
        *ptr = nullptr;
      }
    }
};

int main() {

  // Define pointer handler 
  PointerHandler ptrHdr;

  // Pointers to child classes 
  Child1* child1_0 = nullptr;
  Child1* child1_1 = nullptr;
  Child2* child2_0 = nullptr;
  Child2* child2_1 = nullptr;

  // Initialize pointers 
  ptrHdr.initPointer("child1_0", child1_0);
  ptrHdr.initPointer("child1_1", child1_1);
  ptrHdr.initPointer("child2_1", child2_0);
  ptrHdr.initPointer("child2_1", child2_1);

  std::cout << "Before deletion" << std::endl ;
  std::cout << "child1_0 ptr = " << child1_0 << std::endl;
  std::cout << "child1_1 ptr = " << child1_1 << std::endl;
  std::cout << "child2_1 ptr = " << child2_0 << std::endl;
  std::cout << "child2_1 ptr = " << child2_1 << std::endl;

  // Delete all pointers 
  ptrHdr.deleteAllPointers();

  std::cout << "After deletion" << std::endl ;
  std::cout << "child1_0 ptr = " << child1_0 << std::endl;
  std::cout << "child1_1 ptr = " << child1_1 << std::endl;
  std::cout << "child2_1 ptr = " << child2_0 << std::endl;
  std::cout << "child2_1 ptr = " << child2_1 << std::endl;

  // Init only few now poiters
  ptrHdr.initPointer("child1_0", child1_0);
  ptrHdr.initPointer("child1_1", child1_1);

  // deletion will occur when pointer handler is going out of scope

  return 0;
}

1

There are 1 best solutions below

1
Kai Petzke On

You can avoid the reinterpret_cast completely, if you use an intermittent Parent *:

Child* childPtr = new Child();
Parent* parentPtr = childPtr;        // No cast necessary!
Parent** ptrToChildPtr = &parentPtr;

Furthermore, if you don't need the Child*, because you do all manipulations and access through virtual methods of the parent, then you can leave out the Child* from your code and directly assign the newly created Child to a Parent*:

Parent* new_child = new Child();
Parent** ptrToChildPtr = &parentPtr;

Note, though, that using double pointers in C++ is rare. In most cases, they can and should be completely avoided. In particular, use smart pointers to automatically delete an object and the pointer to it together, instead of keeping pointers around. So, a different and much easier structure to achieve, what you are doing, might be:

std::vector<std::unique_ptr<Parent>> children;

// add children as needed
children.emplace_back(std::make_unique<Child1>("child1_0"));
children.emplace_back(std::make_unique<Child1>("child1_1"));
children.emplace_back(std::make_unique<Child2>("child2_0"));
children.emplace_back(std::make_unique<Child2>("child2_1"));

// cleanup:
children.clear();

// re-add data:
children.emplace_back(std::make_unique<Child1>("child1_processed_0"));
children.emplace_back(std::make_unique<Child1>("child1_processed_1"));

Note, that because your Parent has a virtual destructor, deleting your children through std::unique_ptrs to the Parent class is safe. No memory will be lost, as you can check with valgrind or other memory debuggers.

It is even possible to delete individual elements from your children vector as needed:

children.erase(children.begin() + 1); // This deletes the second child