Home > database >  How to customize a QScopedPointerDeleter to avoid calling destructor of parent class
How to customize a QScopedPointerDeleter to avoid calling destructor of parent class

Time:09-13

I have 2 classes A and B, which looks like this

class A{
  public:
    ~A(){/* do something */};
};

class B : public A{
  public:
    ~B(){/* do something */};
};

I want to avoid calling ~A() when ~B() is called. I found this post said that std::shared_ptr can customize deleter to control destructor. But I'm working on a Qt project which uses QScopedPointer to declare B. Now my question is:
How to customize the QScopedPointerDeleter to avoid calling destructor of parent A?

CodePudding user response:

The good guy

Don't do it. Solve the actual problem in a clean way.

The bad guy - I really want to do it

WARNING Keep in mind that you may get in trouble using this approach, f.ex. by creating memory leaks or undefined behavior.

Note that calling the child destructor ~B, without executing the parent/base destructor ~A isn't possible:

Even when the destructor is called directly (e.g. obj.~Foo();), the return statement in ~Foo() does not return control to the caller immediately: it calls all those member and base destructors first. [1]

However, you can move the logic of ~B to another member function and call that one instead:

class B : public A{
  public:
    ~B(){/* do something */};

    void DestructWithoutParent () {
      /* do something */
      /* call destructor of members*/
    }
};

Note that you should now call the destructor of your members (if any) explicitly.

Now you can release the memory of your B object manually and call your custom destructor function (see this answer for more information and why you shouldn't use this approach):

B *b = new B();
b->DestructWithoutParent (); // calls the 'destructor' of B without calling ~A
operator delete(b); // free memory of b

Note that the heap memory owned by A (f.ex. by smart pointer members of A), isn't released in this way. It may also violate the assumptions made by the programmer of class A, possibly resulting in undefined behavior.

Integrating this with QScopedPointer[2]:

struct BDeleter {
    static inline void cleanup(B *b)
    {
        b->DestructWithoutParent (); // calls the 'destructor' of B without calling ~A
        operator delete(b); // free memory of b
    } 
};

QScopedPointer<B, BDeleter> b(new B);
  •  Tags:  
  • c qt
  • Related