Prevent a parent object's destructor from being called?

Discussion in 'C++' started by Pete C, Oct 27, 2005.

  1. Pete C

    Pete C Guest

    Squeamz wrote:
    > If the answer to my above question is no, does anyone know of an
    > alternative simple solution? I'd prefer to not have to rewrite
    > auto_ptr when the only difference would be the destructor.


    shared_ptr (part of the boost libraries) is a better alternative to
    auto_ptr. It lets you specify a 'deleter' function - ie, a function
    that is called when all references are released in order to delete the
    object. It sounds like what you want:
    http://www.boost.org/libs/smart_ptr/shared_ptr.htm
     
    Pete C, Oct 27, 2005
    #1
    1. Advertising

  2. Pete C

    Ron Natalie Guest

    Squeamz wrote:
    > Hello,
    >
    > Say I create a class ("Child") that inherits from another class
    > ("Parent"). Parent's destructor is not virtual. Is there a way I can
    > prevent Parent's destructor from being called when a Child object goes
    > out of scope?


    The virtual-ness of a destructor has no bearing here. All the
    destructors of the base classes and any non-static members are
    called automatically. There's nothing you can do to stop this.
    >
    > Specifically, I am dealing with a C library that provides a function
    > that must be called to "destruct" a particular struct (this struct is
    > dynamically allocated by another provided function). To avoid memory
    > leaks, I created a class that inherits from std::auto_ptr<[the C
    > struct]>, and I gave it just a constructor and a destructor. The
    > destructor just calls the 3rd-party "destructor" function.
    > Unfortunately the problem is that std::auto_ptr's destructor is not
    > virtual.


    What does the virtualness of have to do with it. The only thing a
    virtual destructor does for you is make destructing through base
    class destructors. auto_ptr isn't appropriate here for the purpose
    anyhow. Auto_ptr calls delete on a single object. Since delete
    appears to be inappropriate, I don't know why you are using it.

    Here:
    class Wrapper {
    public:
    Wrapper() {
    cstruct = C_ConstructorFunction();
    }
    ~Wrapper() {
    C_DestructorFunction(cstruct);
    }
    // you need to define or disable copy constructor
    // and assignement operators as well.
    private:
    CStruct* cstruct;
    };
     
    Ron Natalie, Oct 27, 2005
    #2
    1. Advertising

  3. Pete C

    Squeamz Guest

    Hello,

    Say I create a class ("Child") that inherits from another class
    ("Parent"). Parent's destructor is not virtual. Is there a way I can
    prevent Parent's destructor from being called when a Child object goes
    out of scope?

    Specifically, I am dealing with a C library that provides a function
    that must be called to "destruct" a particular struct (this struct is
    dynamically allocated by another provided function). To avoid memory
    leaks, I created a class that inherits from std::auto_ptr<[the C
    struct]>, and I gave it just a constructor and a destructor. The
    destructor just calls the 3rd-party "destructor" function.
    Unfortunately the problem is that std::auto_ptr's destructor is not
    virtual.

    If the answer to my above question is no, does anyone know of an
    alternative simple solution? I'd prefer to not have to rewrite
    auto_ptr when the only difference would be the destructor.

    Thanks,
    Squeamz
     
    Squeamz, Oct 28, 2005
    #3
  4. Pete C

    Squeamz Guest

    On Thu, 27 Oct 2005 18:41:40 -0400, Ron Natalie <>
    wrote:

    >Squeamz wrote:
    >> Hello,
    >>
    >> Say I create a class ("Child") that inherits from another class
    >> ("Parent"). Parent's destructor is not virtual. Is there a way I can
    >> prevent Parent's destructor from being called when a Child object goes
    >> out of scope?

    >
    >The virtual-ness of a destructor has no bearing here. All the
    >destructors of the base classes and any non-static members are
    >called automatically. There's nothing you can do to stop this.


    Ah, you're right. For some reason I was under the impression that
    only one destructor gets called if the base destructor is virtual.
    Thanks for the info.

    >What does the virtualness of have to do with it. The only thing a
    >virtual destructor does for you is make destructing through base
    >class destructors. auto_ptr isn't appropriate here for the purpose
    >anyhow. Auto_ptr calls delete on a single object. Since delete
    >appears to be inappropriate, I don't know why you are using it.


    Well, I tried to explain my reasoning. Aside from its use of
    'delete', auto_ptr does everything I need here. I wanted to override
    the only part of auto_ptr that uses delete. That's why I was using
    it. Obviously my reasoning was flawed :).

    Your suggestion works, of course, but like I said I didn't want to
    have to deal with writing the assignment operator and stuff.

    Anyway I think I'll take a look at boost's shared_ptr (thanks Pete!).

    Squeamz
     
    Squeamz, Oct 28, 2005
    #4
  5. Pete C

    Kaz Kylheku Guest

    Squeamz wrote:
    > Hello,
    >
    > Say I create a class ("Child") that inherits from another class
    > ("Parent"). Parent's destructor is not virtual. Is there a way I can


    Irrelevant; you aren't deleting a dynamic object through a base class
    pointer.

    > prevent Parent's destructor from being called when a Child object goes
    > out of scope?


    A Child object is a kind of Parent object. So a Parent is going out of
    scope.

    The destructor calls are linked, and that is not under programmer
    control. The only way to break out of it would be to throw an exception
    out of Child::~Child(). That's a bad idea; it would screw up other
    things; don't do that.

    I think you have to use aggregation here or composition rather than
    inheritance. The Child class should have a reference to a Parent.

    > Specifically, I am dealing with a C library that provides a function
    > that must be called to "destruct" a particular struct (this struct is
    > dynamically allocated by another provided function). To avoid memory
    > leaks, I created a class that inherits from std::auto_ptr<[the C
    > struct]>, and I gave it just a constructor and a destructor.


    The problem with this is that auto_ptr destructor will want to call
    delete on whatever pointer is inside it. Inheritance won't fix this
    behavior. The only way to prevent its destructor from doing that is to
    steal that pointer!

    In your own destructor, you take the managed pointer out of the
    auto_ptr base class and replace it with null. Then if the pointer you
    pulled out is non-null, you call the C library's destruction routine.
    If the pointer is null, then the auto_ptr doesn't own any object; you
    do nothing. But if you do this, what's the point of using auto_ptr? You
    are rewriting half of its logic in your own derived class, which
    defeats the point of inheritance.

    Th eproblem

    Here is how to do this silliness:

    class MyClass : public auto_ptr<Whatever> {
    // ...
    public:
    // ...
    ~MyClass() {
    try {
    Whatever *purloined = release();

    if (purloined != 0)
    CLibraryDeleteFunction(purloined);
    } catch (...) {
    // release() threw because there is no pointer!
    }
    }
    };

    Some implementations of auto_ptr throw an exception in release() if the
    object doesn't own any pointer; others just return null, that's why
    there is the try/catch.

    Get it? Your destructor is called first. It calls release() in the base
    class, which takes ownership of the pointer out of auto_ptr and
    replaces it it with null, and returns the original pointer. If the
    return value is non-null it means that the object really did own
    something, and so the C library routine can be called.

    But with all that work, you might as well just complete the above class
    to be a smart pointer in itself, and then get rid of the inheritance
    from auto_ptr.

    The right way with auto_ptr to take advantage of the second template
    parameter in the smart pointer class! That template parameter lets you
    specify a custom allocator class. There is a default value for that
    parameter, so you don't have to deal with it most of the time: the
    default value specifies a class that uses new/delete. You can write
    your own allocator class that uses the C library's functions. There is
    probably code somewhere you can cut and paste for this.

    Another way to deal with this problem is to wrap a C++ management class
    around the object. The C++ class's constructor and destructor call into
    the C library's creation and deletion functions, respectively. A
    pointer to the C object is kept inside this C++ object.

    You can dynamically allocate the C++ object also, and use smart
    pointers to manage that. Of course, there is no need for a special
    allocator because you are using new/delete on the C++ object.
     
    Kaz Kylheku, Oct 28, 2005
    #5
  6. Pete C

    Kaz Kylheku Guest

    Squeamz wrote:
    > Ah, you're right. For some reason I was under the impression that
    > only one destructor gets called if the base destructor is virtual.
    > Thanks for the info.


    The virtual destructor in the base ensures that the destructor call
    through the base goes to the destructor of the most derived class, as
    if that were called directly. From there, all the destructors are
    called in the appropriate order over the entire inheritance lattice!

    > Well, I tried to explain my reasoning. Aside from its use of
    > 'delete', auto_ptr does everything I need here. I wanted to override
    > the only part of auto_ptr that uses delete. That's why I was using
    > it. Obviously my reasoning was flawed :).


    Normally, destructors just take care of clean-up at their level. The
    reason destructors can be virtual is /not/ for the sake of overriding
    base class behavior, as is the case with other virtual functions.

    But you /can/ nervertheless override base class destructor behavior in
    a derived class destructor. You just have to ensure that the base class
    destructur somehow knows that it was done, so it does not try to
    duplicate the job that was taken over, which would result in a
    redundant or otherwise wrongful deallocation.
     
    Kaz Kylheku, Oct 28, 2005
    #6
  7. Pete C

    Ron Natalie Guest

    Squeamz wrote:

    > Well, I tried to explain my reasoning. Aside from its use of
    > 'delete', auto_ptr does everything I need here. I wanted to override
    > the only part of auto_ptr that uses delete. That's why I was using
    > it. Obviously my reasoning was flawed :).


    Other than delete, auto_ptr is just a pointer.
    >
    > Your suggestion works, of course, but like I said I didn't want to
    > have to deal with writing the assignment operator and stuff.


    All you need to do is:
    private:
    Wrapper(const Wrapper&); // Don't implement
    Wrapper& operator=(const Wrapper&); // don't implement

    This will make the object non-copyable in most cases, and should cause
    a linker error for the missing functions in the few cases that don't

    There's also a boost::non_copyable class you can mix in to do
    the same thing (it's just a base class with the same construct that
    "poisons" any object that contains it.
     
    Ron Natalie, Oct 30, 2005
    #7
    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. Felix Wiemann
    Replies:
    9
    Views:
    397
    Martin
    Feb 16, 2005
  2. vivekian
    Replies:
    2
    Views:
    574
    Puppet_Sock
    Mar 24, 2006
  3. Jimmy Hartzell
    Replies:
    0
    Views:
    426
    Jimmy Hartzell
    May 19, 2008
  4. Jimmy Hartzell
    Replies:
    2
    Views:
    1,175
    Jimmy Hartzell
    May 20, 2008
  5. Num GG
    Replies:
    2
    Views:
    380
    Num GG
    Nov 17, 2008
Loading...

Share This Page