deleteing base class after dynamic cast

Discussion in 'C++' started by Nick Keighley, Jan 24, 2007.

  1. Hi,

    Is this code fundamentally broken?

    class B
    {
    }

    class D: public B
    {
    }


    void proc(B* b)
    {
    D* d = dynamic_cast<D*>b;
    // do things to d
    }

    void f()
    {
    B* b = new B;
    proc (b);
    delete b;
    }



    I know it isn't exception safe and should be using RAII (legacy code
    :-( ).
    I'm more worried about which destructor gets called. I assume ~D()
    *doesn't* get called. I assume I should be deleteing D (or better using
    RAII)
    rather than B.

    Unfortunatly B is heavily derived from and changing it will have to be
    in a
    lot of places. But then not fixing it...


    --
    Nick Keighley
     
    Nick Keighley, Jan 24, 2007
    #1
    1. Advertising

  2. Nick Keighley

    Kai-Uwe Bux Guest

    Nick Keighley wrote:

    > Hi,
    >
    > Is this code fundamentally broken?
    >
    > class B
    > {
    > }
    >
    > class D: public B
    > {
    > }
    >
    >
    > void proc(B* b)
    > {
    > D* d = dynamic_cast<D*>b;
    > // do things to d
    > }
    >
    > void f()
    > {
    > B* b = new B;


    Do you mean:

    B* b = new D;

    > proc (b);


    If b does not point to an object of type D, the dynamic_cast in proc should
    barff.

    > delete b;
    > }
    >
    >
    >
    > I know it isn't exception safe and should be using RAII (legacy code
    > :-( ).
    > I'm more worried about which destructor gets called. I assume ~D()
    > *doesn't* get called. I assume I should be deleteing D (or better using
    > RAII)
    > rather than B.
    >
    > Unfortunatly B is heavily derived from and changing it will have to be
    > in a lot of places. But then not fixing it...


    The class B needs to have a virtual destructor. Then deleting derived
    objects via B* will work as it should.


    Best

    Kai-Uwe Bux
     
    Kai-Uwe Bux, Jan 24, 2007
    #2
    1. Advertising

  3. On 24 Jan, 08:54, Kai-Uwe Bux <> wrote:
    > Nick Keighleywrote:


    > > Is this code fundamentally broken?

    >
    > > class B
    > > {
    > > }

    >
    > > class D: public B
    > > {
    > > }

    >
    > > void proc(B* b)
    > > {
    > > D* d = dynamic_cast<D*>b;
    > > // do things to d
    > > }

    >
    > > void f()
    > > {
    > > B* b = new B;

    >
    > Do you mean:
    >
    > B* b = new D;


    er, no I don't think so. I intended to new the base class, cast to the
    derived class
    then delete the base class.

    > > proc (b);If b does not point to an object of type D, the dynamic_cast in proc should

    > barff.


    ?? I thought you could do this with a dynamic_cast?

    > > delete b;
    > > }

    >
    > > I know it isn't exception safe and should be using RAII (legacy code
    > > :-( ).
    > > I'm more worried about which destructor gets called. I assume ~D()
    > > *doesn't* get called. I assume I should be deleteing D (or better using
    > > RAII) rather than B.

    >
    > > Unfortunatly B is heavily derived from and changing it will have to be
    > > in a lot of places. But then not fixing it...

    >
    > The class B needs to have a virtual destructor. Then deleting derived
    > objects via B* will work as it should.


    in reality it does have a virtual DTOR


    --
    Nick Keighley
     
    Nick Keighley, Jan 24, 2007
    #3
  4. Nick Keighley

    Rolf Magnus Guest

    Nick Keighley wrote:

    > On 24 Jan, 08:54, Kai-Uwe Bux <> wrote:
    >> Nick Keighleywrote:

    >
    >> > Is this code fundamentally broken?

    >>
    >> > class B
    >> > {
    >> > }

    >>
    >> > class D: public B
    >> > {
    >> > }

    >>
    >> > void proc(B* b)
    >> > {
    >> > D* d = dynamic_cast<D*>b;
    >> > // do things to d
    >> > }

    >>
    >> > void f()
    >> > {
    >> > B* b = new B;

    >>
    >> Do you mean:
    >>
    >> B* b = new D;

    >
    > er, no I don't think so. I intended to new the base class, cast to the
    > derived class then delete the base class.


    If you only have a B, then why is it a problem that it's not destroyed by
    D's destructor?

    >> > proc (b);If b does not point to an object of type D, the
    >> > dynamic_cast in proc should barff.

    >
    > ?? I thought you could do this with a dynamic_cast?


    Do what? The result of a dynamic_cast<D*>(b) is as follows:

    if the parameter actually points to a D, return a pointer to it
    otherwise return a null pointer

    >> > delete b;
    >> > }
     
    Rolf Magnus, Jan 24, 2007
    #4
  5. Nick Keighley

    Kai-Uwe Bux Guest

    Nick Keighley wrote:

    > On 24 Jan, 08:54, Kai-Uwe Bux <> wrote:
    >> Nick Keighleywrote:

    >
    >> > Is this code fundamentally broken?

    >>
    >> > class B
    >> > {
    >> > }

    >>
    >> > class D: public B
    >> > {
    >> > }

    >>
    >> > void proc(B* b)
    >> > {
    >> > D* d = dynamic_cast<D*>b;
    >> > // do things to d
    >> > }

    >>
    >> > void f()
    >> > {
    >> > B* b = new B;

    >>
    >> Do you mean:
    >>
    >> B* b = new D;

    >
    > er, no I don't think so. I intended to new the base class, cast to the
    > derived class
    > then delete the base class.
    >
    >> > proc (b);If b does not point to an object of type D, the
    >> > dynamic_cast in proc should

    >> barff.

    >
    > ?? I thought you could do this with a dynamic_cast?


    There seems to be a missunderstanding about dynamic_cast<>. In your
    scenario, D is derived from B. That means that every D* automatically
    qualifies as a B*. Therefore, if you have a variable of type B*, its value
    may actually point to a D object. Sometimes, you might know that the actual
    pointee is of type D and you may want to access parts of the object that
    are inaccessible through B. In this case, you can use a pointer cast
    (static_cast<D*> or dynamic_cast<D*>) to tell the compiler that the B*
    variable holds a value that actually is a D* and that the compiler should
    not treat it as such.

    Now, what happens if the B* variable does not actually hold a D* and you
    cast? Well, if you use a static_cast<D*> you get undefined behavior. If you
    use a dynamic_cast<D*> the conversion will yield a null pointer:

    #include <typeinfo>
    #include <iostream>
    #include <iomanip>

    struct B {

    virtual ~B () {};

    };

    struct D : B {};

    int main ( void ) {
    try {
    B* bp = new B;
    D* dp = dynamic_cast<D*>( bp );
    std::cout << std::boolalpha << ( bp == 0 ) << '\n';
    std::cout << std::boolalpha << ( dp == 0 ) << '\n';
    }
    catch ( std::bad_cast & e ) {
    std::cout << e.what() << '\n';
    }
    try {
    B* bp = new B;
    D* dp = static_cast<D*>( bp ); // UB: everything from now on is bogus
    std::cout << std::boolalpha << ( bp == 0 ) << '\n';
    std::cout << std::boolalpha << ( dp == 0 ) << '\n';
    }
    catch ( std::bad_cast & e ) {
    std::cout << e.what() << '\n';
    }
    }

    Either way, casting from B* to D* does not magically turn the pointee into a
    D object if it wasn't one to begin with.


    Best

    Kai-Uwe Bux
     
    Kai-Uwe Bux, Jan 24, 2007
    #5
  6. On 24 Jan, 10:00, Kai-Uwe Bux <> wrote:
    > Nick Keighleywrote:
    > > On 24 Jan, 08:54, Kai-Uwe Bux <> wrote:
    > >> Nick Keighleywrote:


    if the quoting is messed up, google has just been "upgraded" again.
    Do those people test anything?

    > >> > Is this code fundamentally broken?

    >
    > >> > class B
    > >> > {
    > >> > }

    >
    > >> > class D: public B
    > >> > {
    > >> > }

    >
    > >> > void proc(B* b)
    > >> > {
    > >> > D* d = dynamic_cast<D*>b;
    > >> > // do things to d
    > >> > }

    >
    > >> > void f()
    > >> > {
    > >> > B* b = new B;

    >
    > >> Do you mean:

    >
    > >> B* b = new D;

    >
    > > er, no I don't think so. I intended to new the base class, cast to the
    > > derived class then delete the base class.

    >
    > >> > proc (b);If b does not point to an object of type D, the
    > >> > dynamic_cast in proc should barff.

    >
    > > ?? I thought you could do this with a dynamic_cast?There seems to be a missunderstanding about dynamic_cast<>.

    >
    > In your
    > scenario, D is derived from B. That means that every D* automatically
    > qualifies as a B*. Therefore, if you have a variable of type B*, its value
    > may actually point to a D object. Sometimes, you might know that the actual
    > pointee is of type D and you may want to access parts of the object that
    > are inaccessible through B. In this case, you can use a pointer cast
    > (static_cast<D*> or dynamic_cast<D*>) to tell the compiler that the B*
    > variable holds a value that actually is a D* and that the compiler should
    > not treat it as such.
    >
    > Now, what happens if the B* variable does not actually hold a D* and you
    > cast? Well, if you use a static_cast<D*> you get undefined behavior. If you
    > use a dynamic_cast<D*> the conversion will yield a null pointer:
    >
    > #include <typeinfo>
    > #include <iostream>
    > #include <iomanip>
    >
    > struct B {
    >
    > virtual ~B () {};
    >
    > };struct D : B {};
    >
    > int main ( void ) {
    > try {
    > B* bp = new B;
    > D* dp = dynamic_cast<D*>( bp );
    > std::cout << std::boolalpha << ( bp == 0 ) << '\n';
    > std::cout << std::boolalpha << ( dp == 0 ) << '\n';
    > }
    > catch ( std::bad_cast & e ) {
    > std::cout << e.what() << '\n';
    > }
    > try {
    > B* bp = new B;
    > D* dp = static_cast<D*>( bp ); // UB: everything from now on is bogus
    > std::cout << std::boolalpha << ( bp == 0 ) << '\n';
    > std::cout << std::boolalpha << ( dp == 0 ) << '\n';
    > }
    > catch ( std::bad_cast & e ) {
    > std::cout << e.what() << '\n';
    > }
    >
    > }
    >
    > Either way, casting from B* to D* does not magically turn the pointee into a
    > D object if it wasn't one to begin with.


    right. Brain fart. The real code did indeed new D.


    class B
    {
    }

    class D: public B
    {
    }


    void proc(B* b)
    {
    D* d = dynamic_cast<D*>b;
    // do things to d
    }

    void f()
    {
    B* b = new D;
    proc (b);
    delete b;
    }


    my only excuse (besides temporary insanity) is that the new was hidden
    in a factory method.

    thankyou for you patience.


    --
    Nick Keighley
     
    Nick Keighley, Jan 24, 2007
    #6
  7. Nick Keighley

    Mark P Guest

    Nick Keighley wrote:
    > On 24 Jan, 10:00, Kai-Uwe Bux <> wrote:
    >> Nick Keighleywrote:
    >>> On 24 Jan, 08:54, Kai-Uwe Bux <> wrote:
    >>>> Nick Keighleywrote:

    >
    > if the quoting is messed up, google has just been "upgraded" again.
    > Do those people test anything?
    >
    >>>>> Is this code fundamentally broken?
    >>>>> class B
    >>>>> {
    >>>>> }
    >>>>> class D: public B
    >>>>> {
    >>>>> }
    >>>>> void proc(B* b)
    >>>>> {
    >>>>> D* d = dynamic_cast<D*>b;
    >>>>> // do things to d
    >>>>> }
    >>>>> void f()
    >>>>> {
    >>>>> B* b = new B;
    >>>> Do you mean:
    >>>> B* b = new D;
    >>> er, no I don't think so. I intended to new the base class, cast to the
    >>> derived class then delete the base class.
    >>>>> proc (b);If b does not point to an object of type D, the
    >>>>> dynamic_cast in proc should barff.
    >>> ?? I thought you could do this with a dynamic_cast?There seems to be a missunderstanding about dynamic_cast<>.

    >> In your
    >> scenario, D is derived from B. That means that every D* automatically
    >> qualifies as a B*. Therefore, if you have a variable of type B*, its value
    >> may actually point to a D object. Sometimes, you might know that the actual
    >> pointee is of type D and you may want to access parts of the object that
    >> are inaccessible through B. In this case, you can use a pointer cast
    >> (static_cast<D*> or dynamic_cast<D*>) to tell the compiler that the B*
    >> variable holds a value that actually is a D* and that the compiler should
    >> not treat it as such.
    >>
    >> Now, what happens if the B* variable does not actually hold a D* and you
    >> cast? Well, if you use a static_cast<D*> you get undefined behavior. If you
    >> use a dynamic_cast<D*> the conversion will yield a null pointer:
    >>
    >> #include <typeinfo>
    >> #include <iostream>
    >> #include <iomanip>
    >>
    >> struct B {
    >>
    >> virtual ~B () {};
    >>
    >> };struct D : B {};
    >>
    >> int main ( void ) {
    >> try {
    >> B* bp = new B;
    >> D* dp = dynamic_cast<D*>( bp );
    >> std::cout << std::boolalpha << ( bp == 0 ) << '\n';
    >> std::cout << std::boolalpha << ( dp == 0 ) << '\n';
    >> }
    >> catch ( std::bad_cast & e ) {
    >> std::cout << e.what() << '\n';
    >> }
    >> try {
    >> B* bp = new B;
    >> D* dp = static_cast<D*>( bp ); // UB: everything from now on is bogus
    >> std::cout << std::boolalpha << ( bp == 0 ) << '\n';
    >> std::cout << std::boolalpha << ( dp == 0 ) << '\n';
    >> }
    >> catch ( std::bad_cast & e ) {
    >> std::cout << e.what() << '\n';
    >> }
    >>
    >> }
    >>
    >> Either way, casting from B* to D* does not magically turn the pointee into a
    >> D object if it wasn't one to begin with.

    >
    > right. Brain fart. The real code did indeed new D.
    >
    >
    > class B
    > {
    > }
    >
    > class D: public B
    > {
    > }
    >
    >
    > void proc(B* b)
    > {
    > D* d = dynamic_cast<D*>b;
    > // do things to d
    > }
    >
    > void f()
    > {
    > B* b = new D;
    > proc (b);
    > delete b;
    > }
    >
    >
    > my only excuse (besides temporary insanity) is that the new was hidden
    > in a factory method.
    >
    > thankyou for you patience.
    >
    >


    Not sure if your question still stands, but the dynamic cast doesn't
    really cause any problems here (it doesn't really "do" anything, in
    fact, since b is a D). The only glaring pitfall in the code you've
    shown is the lack of a virtual destructor for B.
     
    Mark P, Jan 24, 2007
    #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. Emilio

    Problem deleteing files

    Emilio, Oct 23, 2003, in forum: ASP .Net
    Replies:
    3
    Views:
    372
    Rajesh.V
    Oct 23, 2003
  2. Blue Ocean

    Deleteing automatic variables

    Blue Ocean, Jul 10, 2004, in forum: C++
    Replies:
    3
    Views:
    381
    Howard
    Jul 12, 2004
  3. Replies:
    1
    Views:
    407
    Thomas Matthews
    Jul 12, 2004
  4. Replies:
    5
    Views:
    505
    John Carson
    Mar 14, 2005
  5. Pavel
    Replies:
    7
    Views:
    563
    Pavel
    Sep 19, 2010
Loading...

Share This Page