delete MyClass doing more than MyClass::operator delete()?

Discussion in 'C++' started by tom, Jul 14, 2006.

  1. tom

    tom Guest

    Hi,
    I'm overriding my operator new and operator delete for two classes,
    one inherited from the other, so I can use my own memory pool. A
    simplified version of what I have is below:


    class BaseClass {
    BaseClass();
    virtual ~BaseClass();
    virtual void baseFunction();
    static void operator delete(void* mem);
    };

    class InheritedClass : public BaseClass {
    IneritedClass();
    ~InheritedClass();
    void baseFunction();
    void nonBaseFunction();
    static void operator delete(void* mem);
    };


    I'm testing some things by making operator delete() do nothing, so the
    memory shouldn't be deallocated. I've also made the ~BaseClass() and
    ~InheritedClass() functions do nothing. When I call delete on an
    InheritedClass object, if I try to then call any inherited function on
    that object (in this example, baseFunction()) I get a crash. If I call
    a non-inherited function (nonBaseFunction() in this example) then it
    goes along fine and nothing bad happens, as I would epect the inherited
    function to have done (since, again, no memory should be deallocated).
    In my actual code, I've tested to make sure that the delete call is
    actually going through my InheritedClass's operator delete function,
    and that it isn't doing anything in the base class's operator delete
    function, though both have them defined to do nothing. But it seems
    that delete is doing something more than what I define in that
    function, and it's messing up things dealing with inheritance. I'm
    using Visual Studio 2005. Any ideas would be greatly appreciated.

    Tom
     
    tom, Jul 14, 2006
    #1
    1. Advertising

  2. tom wrote:
    > I'm overriding my operator new and operator delete for two classes,
    > one inherited from the other, so I can use my own memory pool. A
    > simplified version of what I have is below:
    >
    >
    > class BaseClass {
    > BaseClass();
    > virtual ~BaseClass();
    > virtual void baseFunction();
    > static void operator delete(void* mem);
    > };
    >
    > class InheritedClass : public BaseClass {
    > IneritedClass();
    > ~InheritedClass();
    > void baseFunction();
    > void nonBaseFunction();
    > static void operator delete(void* mem);
    > };
    >
    >
    > I'm testing some things by making operator delete() do nothing, so the
    > memory shouldn't be deallocated. I've also made the ~BaseClass() and
    > ~InheritedClass() functions do nothing. When I call delete on an
    > InheritedClass object, if I try to then call any inherited function on
    > that object (in this example, baseFunction()) I get a crash. If I
    > call a non-inherited function (nonBaseFunction() in this example)
    > then it goes along fine and nothing bad happens, as I would epect the
    > inherited function to have done (since, again, no memory should be
    > deallocated). In my actual code, I've tested to make sure that the
    > delete call is actually going through my InheritedClass's operator
    > delete function, and that it isn't doing anything in the base class's
    > operator delete function, though both have them defined to do
    > nothing. But it seems that delete is doing something more than what
    > I define in that function, and it's messing up things dealing with
    > inheritance. I'm using Visual Studio 2005. Any ideas would be
    > greatly appreciated.


    Calling non-static member functions for an object after its lifetime
    ended has *undefined behaviour* according to the language specification.
    What else do you need to know about it?

    If you'd like to learn what your code does under the covers, by all
    means, explore the generated machine code and make your own conclusions
    from that. However, it has no relevance here, in comp.lang.c++. Any
    conclusion you make from looking at machine code is only relevant to
    your particular platform (hardware and OS) and your particular compiler
    implementation.

    V
    --
    Please remove capital 'A's when replying by e-mail
    I do not respond to top-posted replies, please don't ask
     
    Victor Bazarov, Jul 14, 2006
    #2
    1. Advertising

  3. tom

    petke Guest

    My guess is that the compiler destroys the vtable on its own. So the
    vtable pointer in your object now points to memory that has been
    destroyed. Programmers dont have access to the vtable so they cant be
    excpected to create and destroy it when writing their own new and
    delete. The programmers part is creating or destroying the object, not
    its vtable.

    Since baseFunction is a virtual function it crashes when trying to
    access the vtable, the nonBaseFunction does not use the vtable so does
    not crash.

    Using an object after calling delete (even an empty one) sure sounds
    like undefined behaviour to me.

    Then again I'm no expert.

    Regards /Petke
     
    petke, Jul 14, 2006
    #3
  4. tom

    Ron Natalie Guest

    tom wrote:

    Despite the unfortunate and stupid name, the functions operator new and
    operator delete are not the implementation of the new and delete
    operators. They are the memory allocator/deallocator functions.

    > I'm testing some things by making operator delete() do nothing, so the
    > memory shouldn't be deallocated.


    The memory is not deallocationed.

    > f I try to then call any inherited function on
    > that object (in this example, baseFunction()) I get a crash.


    Unfortunately, just stubbing out the destructors and the delete
    operators do not totally negate the operation of the delete
    operator.

    There are a number of things that happen during initialization
    and destruction other than the invocation of the destructor
    bodies and the call to operator delete() to return memory.

    The truth of the matter as far as the standard is concerned
    is that once the objects lifetime is over, you can't do
    stuff with it. Yes you could look at the deleted memory
    directly, but the object will not necessarily support any
    attempts to use it as an object.

    I can tell you why it probably blows up in practice, but that
    knowledge is dangerous to you. You should not touch the
    object after it has been deleted.


    If you want to manage an object lifetime, the key is to not
    use the allocation / deallocation functions. For instance,
    if you want to reference count the object, you just add
    functions to INCREASE/DECREASE and let the decrease delete
    the object on last use:

    class Counted {
    public:
    Counted() : references(0) { } // init reference count
    private:
    ~Counted() { } // no external destruction.

    public:
    void AddReference() { ++references; }
    void SubReference() { if(--reference == 0) delete this; }
    };

    If you want to use normal object creation / destruction procedures, you
    can wrap this whole thing with a helper object that holds a pointer
    to Counted and increases and decreases the reference count in it's
    constructors, copy constructor, assignment operator, and destructor.

    There's several of these type objects already defined and debugged
    for you in the boost library.
     
    Ron Natalie, Jul 14, 2006
    #4
  5. tom

    Protoman Guest

    Ron Natalie wrote:
    > tom wrote:
    >
    > Despite the unfortunate and stupid name, the functions operator new and
    > operator delete are not the implementation of the new and delete
    > operators. They are the memory allocator/deallocator functions.
    >
    > > I'm testing some things by making operator delete() do nothing, so the
    > > memory shouldn't be deallocated.

    >
    > The memory is not deallocationed.
    >
    > > f I try to then call any inherited function on
    > > that object (in this example, baseFunction()) I get a crash.

    >
    > Unfortunately, just stubbing out the destructors and the delete
    > operators do not totally negate the operation of the delete
    > operator.
    >
    > There are a number of things that happen during initialization
    > and destruction other than the invocation of the destructor
    > bodies and the call to operator delete() to return memory.
    >
    > The truth of the matter as far as the standard is concerned
    > is that once the objects lifetime is over, you can't do
    > stuff with it. Yes you could look at the deleted memory
    > directly, but the object will not necessarily support any
    > attempts to use it as an object.
    >
    > I can tell you why it probably blows up in practice, but that
    > knowledge is dangerous to you. You should not touch the
    > object after it has been deleted.
    >
    >
    > If you want to manage an object lifetime, the key is to not
    > use the allocation / deallocation functions. For instance,
    > if you want to reference count the object, you just add
    > functions to INCREASE/DECREASE and let the decrease delete
    > the object on last use:
    >
    > class Counted {
    > public:
    > Counted() : references(0) { } // init reference count
    > private:
    > ~Counted() { } // no external destruction.
    >
    > public:
    > void AddReference() { ++references; }
    > void SubReference() { if(--reference == 0) delete this; }
    > };
    >
    > If you want to use normal object creation / destruction procedures, you
    > can wrap this whole thing with a helper object that holds a pointer
    > to Counted and increases and decreases the reference count in it's
    > constructors, copy constructor, assignment operator, and destructor.
    >
    > There's several of these type objects already defined and debugged
    > for you in the boost library.


    Here's a thread on this *interesting* subject:

    http://groups.google.com/group/comp...q=reference counting&rnum=11#2d300689619ed391
     
    Protoman, Jul 14, 2006
    #5
  6. tom

    tom Guest

    Ah, thanks so much for this clarification. It is an unfortunate and
    stupid name for these operators, I've been using them for a long time
    assuming that I was completely overriding the delete functionality and
    just now came to a spot where it was clear I wasn't. Very helpful
    remarks, thank you all very much!!


    > Despite the unfortunate and stupid name, the functions operator new and
    > operator delete are not the implementation of the new and delete
    > operators. They are the memory allocator/deallocator functions.
     
    tom, Jul 14, 2006
    #6
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Mario Fratelli
    Replies:
    32
    Views:
    1,456
    Phlip
    Dec 9, 2003
  2. Dave
    Replies:
    1
    Views:
    367
    Ron Natalie
    Dec 8, 2003
  3. modemer
    Replies:
    11
    Views:
    658
    modemer
    Mar 21, 2005
  4. Gunnar G
    Replies:
    5
    Views:
    393
    Howard
    Jul 8, 2005
  5. Replies:
    3
    Views:
    447
    Alex Vinokur
    Jan 19, 2007
Loading...

Share This Page