Double Dan
Double Dan

Reputation: 151

Delete this after cleanup

class BaseTest {
protected:
  virtual void finalizeParts() {
      delete m_part;
  };
public:
  int* m_part;

  BaseTest() {
    m_part = new int;
  }

  void finalize() {
    finalizeParts();
    delete this;
  }
};

class SubTest : public BaseTest {
protected:
  void finalizeParts() {
      BaseTest::finalizeParts();
      delete m_anotherPart;
  }
public:
  int* m_anotherPart;

  SubTest() {
    m_anotherPart = new int;
  }
};

SubTest* test = new SubTest();
test->finalize();

I am having trouble avoiding virtual function calls inside the destructor of my classes (I hate that C++ forces me to do this in the first place). Overriding the destructor in all my subclasses seems terribly inconvenient compared to a common cleanup strategy in a base class using some virtual functions that can be overridden if needed. As a workaround I'm thinking about introducing a 'finalize' function in my base class that performs the cleanup and finally calls 'delete this'. It's probably a very unusual solution, so I was wondering if I'm approaching this the wrong way and if there's a more obvious way to write 'proper' destructors in C++.

Upvotes: 0

Views: 122

Answers (3)

Casey
Casey

Reputation: 42554

Is this any simpler to you?

class BaseTest {
public:
  std::unique_ptr<int> m_part;

  BaseTest() : m_part(new int) {}
  virtual ~BaseTest() {}
};

class SubTest : public BaseTest {
public:
  std::unique_ptr<int> m_anotherPart;

  SubTest() : m_anotherPart(new int) {}
};

SubTest test;

or for that matter,

class BaseTest {
public:
  int m_part;
};

class SubTest : public BaseTest {
public:
  int m_anotherPart;
};

SubTest test;

I think you have an XY problem. Instead of asking us about your weird reimplementation-of-what-destructors-already-do, ask about the problem you are having with calling virtual functions in your destructors.

Upvotes: 0

Ilya Kobelevskiy
Ilya Kobelevskiy

Reputation: 5345

Your approach is wrong.

With virtual destructors, destructor of base class will be called as well as destructor of derived class - so you should implement destructor for each derived class, that would delete only relevant portion of derived class, and let destructor of base class to clean base class.

If you have a chain of derived classes, destructor for each level of inheritance will be called - in order from most derived class to the base class.

For your example, all that required is:

class BaseTest {
public:
  virtual ~BaseTest () {
      delete m_part;
  };
  int* m_part;

  BaseTest() {
    m_part = new int;
  }
};

class SubTest : public BaseTest {
 public:
  virtual ~SubTest () {
      //~BaseTest() will be called automatically
      delete m_anotherPart;
  }
  int* m_anotherPart;

  SubTest() {
    m_anotherPart = new int;
  }
};

SubTest* test = new SubTest();
delete test;

Upvotes: 1

Artem Sobolev
Artem Sobolev

Reputation: 6079

If your object aggregates other objects that manage their resources (think of smart pointers, for example. General principle is called RAII), then there is no need in destructor at all.

Of course, you still need desructor for each such "manager" but it should be much easier to implement because of less information and resources to concern about.

self-deleting in your case seems to be bad approach since no one would expect finalize to free object's memory (principle of least astonishment). Though it may be okay with internal implementation (For example, I once did delete this when was implementing shared_ptr's. Namely, I did it when counter of resource manager reaches 0. But that behavior wasn't exposed to end-user anyway)

Upvotes: 1

Related Questions