Graeme.Dixon%newcastle.ac.uk@NSS.CS.UCL.AC.UK (Graeme Dixon) (04/10/89)
There is a bug in the code generated by g++ when the delete operator is overloaded that results in the delete operator being called once for each derived class in a hierarchy. The following program illustrates the bug: #include <stream.h> class A { public: A() { cout << "A::A\n"; } ~A() { cout << "A::~A\n"; } void* operator new(long size) { cout << "A::new\n"; return malloc(size); } void operator delete(A* todel) { cout << "A::delete\n"; free(todel); } }; class B: public A { public: B() { cout << "B::B\n"; } ~B() { cout << "B::~B\n"; } }; class C: public B { public: C() { cout << "C::C\n"; } ~C() { cout << "C::~C\n"; } }; main() { B *b = new B; delete b; // OK C *c = new C; delete c; // not OK - delete called twice } and produces the following when compiled with g++ (version 1.34.0) and linked with /usr/lib/debug/malloc.o (using g++ -o bug bug.cc /usr/lib/debug/malloc.o): A::new A::A B::B B::~B A::~A A::delete A::new A::A B::B C::C C::~C B::~B A::~A A::delete A::delete free: block 0x21804 was already free Abort (core dumped) Each successively derived class results in an additional invocation of the delete operator when an instance of that class is deleted. Graeme Dixon - Computing Laboratory, University of Newcastle upon Tyne, UK JANET = Graeme.Dixon@uk.ac.newcastle ARPA = GraemeDixon@newcastle.ac.uk UUCP = ...!ukc!newcastle.ac.uk!Graeme.Dixon PHONE = +44 91 222 8067
tiemann@YAHI.STANFORD.EDU (Michael Tiemann) (04/10/89)
Here is a fix for GNU C++ wrt overloading operator delete. Your line numbers will vary. yahi% diff -c2 cplus-init.c~ cplus-init.c *** cplus-init.c~ Sun Apr 2 04:03:25 1989 --- cplus-init.c Mon Apr 10 09:20:40 1989 *************** *** 2600,2603 **** --- 2604,2608 ---- tree exprstmt = NULL_TREE; tree parent_auto_delete = auto_delete; + tree cond; /* If this type does not have a destructor, but does have *************** *** 2608,2616 **** { parent_auto_delete = integer_zero_node; ! expr = build_opfncall (DELETE_EXPR, addr, addr); ! if (expr == error_mark_node) ! return error_mark_node; ! exprstmt = build_tree_list (NULL_TREE, expr); } if (basetype && TYPE_NEEDS_DESTRUCTOR (basetype)) --- 2613,2641 ---- { parent_auto_delete = integer_zero_node; ! if (auto_delete == integer_zero_node) ! cond = NULL_TREE; ! else ! { ! expr = build_opfncall (DELETE_EXPR, addr, addr); ! if (expr == error_mark_node) ! return error_mark_node; ! if (auto_delete != integer_one_node) ! cond = build (COND_EXPR, void_type_node, ! build (NE_EXPR, integer_type_node, auto_delete, integer_zero_node), ! expr, ! build (NOP_EXPR, void_type_node, integer_zero_node)); ! else cond = expr; ! } ! } ! else if (basetype == NULL_TREE ! || ! TYPE_NEEDS_DESTRUCTOR (basetype)) ! { ! cond = build (COND_EXPR, void_type_node, ! build (NE_EXPR, integer_type_node, auto_delete, integer_zero_node), ! build_function_call (BID, build_tree_list (NULL_TREE, addr)), ! build (NOP_EXPR, void_type_node, integer_zero_node)); } + if (cond) + exprstmt = build_tree_list (NULL_TREE, cond); if (basetype && TYPE_NEEDS_DESTRUCTOR (basetype)) *************** *** 2625,2639 **** exprstmt); } - else - { - tree cond = build (COND_EXPR, void_type_node, - build (NE_EXPR, integer_type_node, auto_delete, integer_zero_node), - (TREE_GETS_DELETE (type) - ? build_opfncall (DELETE_EXPR, addr, addr) - : build_function_call (BID, build_tree_list (NULL_TREE, addr))), - build (NOP_EXPR, void_type_node, integer_zero_node)); - - exprstmt = build_tree_list (NULL_TREE, cond); - } for (i = 2; i <= n_baseclasses; i++) --- 2650,2653 ---- Michael