Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

New/delete operator overload and base class

whI have a big headache at the moment.

Basically I have this :

Class A -> Class B
Class A -> Class C
Class A -> Class D

Class E with constructor with declaration E(int, A *objptr, bool IsObjPtrOwner = true)

As you see B C and D inherit from A, A being the base class. Class D must have a specific alignment (because SSE2 is used inside it), hence why I overloaded new/delete inside it, providing an aligned block of memory each time the object is dynamically allcated. Should also I mention since A B C and D differ, I would pretty much guess B C A and D do not have the same size at all.

So I would like to be able to do that:

E eobj(12, new D(2.001), true);

Because the parameter IsObjPtrOwner would be true, I programmed my class E so that, if the member m_IsObjPtrOwner is true, the pointer m_objptr is deleted inside the destructor of E.

This would be very convenient for me to be able to dynamically allocate one of the derived classes of A directly while constructing the object E, and not have to care about it later. The reason for this is that I will be making a lot of instances of class E throughout my program, each time with a different B/C/D instance. So I would like not to have to keep a copy of each pointer I create each time I construct an instance of E.

So I tried to make new/delete operators pure virtual, but it just won't work. The damn functions must be static, very bothering. So I tried to circumvent this as much as I could, but I ended up discovering I cannot use "this" inside static functions.

What can I do? How can I realize this dream? I have a dream...


EDIT: For some reasons people do not understand at all what I'm trying to say.

I have a base class A and a set of derived classes B/C/D from A. I have a class E taking as an argument in its constructor a pointer of class A, which is then stored in a member, say m_bcdobj, so I have this :

class B : public A {
    B(double x) : m_x(x) { bla bla bla}
    void *operator new(size_t size)   { return Util_MemAlign(size, 4); }
    void  operator delete(void* ptr)  { Util_AlignFree(ptr); }
}
class C : public A {
    C(double x) : m_x(x) { bla bla bla}
    void *operator new(size_t size)   { return malloc(size); }
    void  operator delete(void* ptr)  { free(ptr); }
}
class D : public A {
    D(double x) : m_x(x) { bla bla bla}
    void *operator new(size_t size)   { return Util_MemAlign(size, 16); }
    void  operator delete(void* ptr)  { Util_AlignFree(ptr); }
}

As you see, each of em have different alignment requirements.

Now I have a class E:

class E {
    public:
        E(int z, A *bcdobj, bool IsObjPtrOwner = true) : m_z(z), m_bcdobj(bcdobj), m_freebcd(IsObjPtrOwner) { bla bla bla }

        ~E() { if (m_freebcd) { delete m_bcdobj; } }

    private:
        A *m_bcdobj;
        int m_z;
        bool m_freebcd;
}

So I want to be able to do that:

E einst(2, new D(2.001));

i.e. I don't keep a copy of the D object allocated. The allocated D object would be freed while "einst" is destroyed. The problem is that this code will not work. When deleting m_bcdobj inside ~E(), the overloaded delete operator inside D will not be called.

Thanks!

like image 934
Yannick Avatar asked Aug 10 '26 14:08

Yannick


1 Answers

operator delete is special in that despite being a static member, if the class has a virtual destructor it is dynamically dispatched. §12.5 [class.free]/p4:

If the delete-expression is used to deallocate a class object whose static type has a virtual destructor, the deallocation function is the one selected at the point of definition of the dynamic type’s virtual destructor (12.4).

For example,

struct B {
    virtual ~B() = default;
    void operator delete(void* ptr) { 
        std::cout << "B's operator delete" << std::endl; ::operator delete(ptr); 
    }
};
struct D : B {
    void operator delete(void* ptr) { 
        std::cout << "D's operator delete" << std::endl; ::operator delete(ptr); 
    }
};
int main() {
    B* bp = new D;
    delete bp; //1: uses D::operator delete(void*)
}

prints:

D's operator delete

Thus, give A a virtual destructor and you should see the correct operator delete called :).

like image 186
T.C. Avatar answered Aug 13 '26 03:08

T.C.



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!