Not what I expected from some exception code (throw/try/catch)

Discussion in 'C++' started by stevewilliams2004@comcast.net, Jul 16, 2007.

  1. Guest

    I was wondering if someone could explain the output I am getting for
    the program below. What I expected from the main program output was
    "Cat" but instead I see "Mammal". The output is also included below.
    I got the same results with GCC 3.4.4 under cygwin as with MSDev
    studio 2003. Even stranger to me, if I change the catch statement to
    catch a Cat instead of a Mammal, the program crashes in the catch
    body, during the call to m.MyType(). Thanks for any explanations in
    advance.

    Program:

    #include <iostream>
    using namespace std;

    class Mammal
    {
    public:
    Mammal()
    {
    cout << "Constructing Mammal @ " << this << endl;
    }
    Mammal(const Mammal& source)
    {
    cout << "Copy Constructing Mammal @ " << this << " from " <<
    &source << endl;
    }
    ~Mammal()
    {
    cout << "Destructing Mammal @ " << this << endl;
    }
    virtual const char* MyType()
    {
    return "Mammal";
    }
    };
    class Cat : public Mammal
    {
    public:
    Cat()
    {
    cout << "Constructing Cat @ " << this << endl;
    }
    Cat(const Cat& source)
    {
    cout << "Copy Constructing Cat @ " << this << " from " <<
    &source << endl;
    }
    ~Cat()
    {
    cout << "Destructing Cat @ " << this << endl;
    }

    virtual const char* MyType()
    {
    return "Cat";
    }
    };

    int main(int argc, char *argv[])
    {
    Cat fluffy;
    Mammal &fluffyRef = fluffy;
    try
    {
    throw fluffyRef;
    }
    catch (Mammal &m)
    {
    cout << "Caught a " << m.MyType() << endl;
    return 0;
    }
    cout << "Nothing Caught" << endl;
    return 0;
    }

    Output:

    Steve@nessus /cygdrive/f/dev/src/TestWorkspace
    $ ./TestWorkspace.exe
    Constructing Mammal @ 0x22ccc0
    Constructing Cat @ 0x22ccc0
    Copy Constructing Mammal @ 0xc306d8 from 0x22ccc0
    Caught a Mammal
    Destructing Mammal @ 0xc306d8
    Destructing Cat @ 0x22ccc0
    Destructing Mammal @ 0x22ccc0
     
    , Jul 16, 2007
    #1
    1. Advertising

  2. * :
    > I was wondering if someone could explain the output I am getting for
    > the program below. What I expected from the main program output was
    > "Cat" but instead I see "Mammal". The output is also included below.
    > I got the same results with GCC 3.4.4 under cygwin as with MSDev
    > studio 2003. Even stranger to me, if I change the catch statement to
    > catch a Cat instead of a Mammal, the program crashes


    It would, yes, because the exception is then not caught and propagates
    out of "main".


    > in the catch
    > body, during the call to m.MyType().


    This I believe is a hypothesis of yours, and an incorrect one.


    > Thanks for any explanations in
    > advance.
    >
    > Program:
    >
    > #include <iostream>
    > using namespace std;
    >
    > class Mammal
    > {
    > public:
    > Mammal()
    > {
    > cout << "Constructing Mammal @ " << this << endl;
    > }
    > Mammal(const Mammal& source)
    > {
    > cout << "Copy Constructing Mammal @ " << this << " from " <<
    > &source << endl;
    > }
    > ~Mammal()
    > {
    > cout << "Destructing Mammal @ " << this << endl;
    > }
    > virtual const char* MyType()
    > {
    > return "Mammal";
    > }
    > };
    > class Cat : public Mammal
    > {
    > public:
    > Cat()
    > {
    > cout << "Constructing Cat @ " << this << endl;
    > }
    > Cat(const Cat& source)
    > {
    > cout << "Copy Constructing Cat @ " << this << " from " <<
    > &source << endl;
    > }
    > ~Cat()
    > {
    > cout << "Destructing Cat @ " << this << endl;
    > }
    >
    > virtual const char* MyType()
    > {
    > return "Cat";
    > }
    > };
    >
    > int main(int argc, char *argv[])
    > {
    > Cat fluffy;
    > Mammal &fluffyRef = fluffy;
    > try
    > {
    > throw fluffyRef;


    Formally, this copy constructs a Mammal to some Mammal instance (the
    exception object) provided by the runtime support.

    C++ "throw" is by value.


    > }
    > catch (Mammal &m)


    If you don't intend to modify the object, catch by reference to const.
    That way you document your intentions, in the source code. Which is
    generally the best place to document such low-level details.


    > {
    > cout << "Caught a " << m.MyType() << endl;
    > return 0;
    > }
    > cout << "Nothing Caught" << endl;
    > return 0;
    > }


    Hth.,

    - Alf

    --
    A: Because it messes up the order in which people normally read text.
    Q: Why is it such a bad thing?
    A: Top-posting.
    Q: What is the most annoying thing on usenet and in e-mail?
     
    Alf P. Steinbach, Jul 16, 2007
    #2
    1. Advertising

  3. Kai-Uwe Bux Guest

    wrote:

    > I was wondering if someone could explain the output I am getting for
    > the program below. What I expected from the main program output was
    > "Cat" but instead I see "Mammal". The output is also included below.
    > I got the same results with GCC 3.4.4 under cygwin as with MSDev
    > studio 2003. Even stranger to me, if I change the catch statement to
    > catch a Cat instead of a Mammal, the program crashes in the catch
    > body, during the call to m.MyType(). Thanks for any explanations in
    > advance.
    >
    > Program:
    >
    > #include <iostream>
    > using namespace std;
    >
    > class Mammal
    > {
    > public:
    > Mammal()
    > {
    > cout << "Constructing Mammal @ " << this << endl;
    > }
    > Mammal(const Mammal& source)
    > {
    > cout << "Copy Constructing Mammal @ " << this << " from " <<
    > &source << endl;
    > }
    > ~Mammal()
    > {
    > cout << "Destructing Mammal @ " << this << endl;
    > }
    > virtual const char* MyType()
    > {
    > return "Mammal";
    > }
    > };
    > class Cat : public Mammal
    > {
    > public:
    > Cat()
    > {
    > cout << "Constructing Cat @ " << this << endl;
    > }
    > Cat(const Cat& source)
    > {
    > cout << "Copy Constructing Cat @ " << this << " from " <<
    > &source << endl;
    > }
    > ~Cat()
    > {
    > cout << "Destructing Cat @ " << this << endl;
    > }
    >
    > virtual const char* MyType()
    > {
    > return "Cat";
    > }
    > };
    >
    > int main(int argc, char *argv[])
    > {
    > Cat fluffy;
    > Mammal &fluffyRef = fluffy;
    > try
    > {
    > throw fluffyRef;


    You throw a Mamal. At this point, a temporary Mamal is created and
    initialized from fluffyRef, which involves slicing. See [15.1/3]:

    A throw-expression initializes a temporary object, called the exception
    object, the type of which is determined by removing any top-level
    cv-qualifiers from the static type of the operand of throw and adjusting
    the type from ?array of T? or ?function returning T? to ?pointer to T?
    or ?pointer to function returning T?, respectively.

    Note that the _static type_ is used for the temporary.

    Also note that a temporary copy is needed since the original is a local
    object that has to go down during stack unwinding.


    > }
    > catch (Mammal &m)


    At this point, the temporary implicitly created in the throw() is used to
    initialize the Mamal& here. Since slicing already happened, you don't get a
    Cat.

    > {
    > cout << "Caught a " << m.MyType() << endl;
    > return 0;
    > }
    > cout << "Nothing Caught" << endl;
    > return 0;
    > }
    >
    > Output:
    >
    > Steve@nessus /cygdrive/f/dev/src/TestWorkspace
    > $ ./TestWorkspace.exe
    > Constructing Mammal @ 0x22ccc0
    > Constructing Cat @ 0x22ccc0
    > Copy Constructing Mammal @ 0xc306d8 from 0x22ccc0
    > Caught a Mammal
    > Destructing Mammal @ 0xc306d8
    > Destructing Cat @ 0x22ccc0
    > Destructing Mammal @ 0x22ccc0




    Best

    Kai-Uwe Bux
     
    Kai-Uwe Bux, Jul 16, 2007
    #3
  4. Guest


    > It would, yes, because the exception is then not caught and propagates
    > out of "main".
    >
    > > in the catch
    > > body, during the call to m.MyType().

    >
    > This I believe is a hypothesis of yours, and an incorrect one.


    Nope - I verified this with a debugger. The MSDev debugger crashed on
    the call m.MyType(), and in cygwin I got the cout just prior to the
    call and not the one after it.

    Also - looking with the MSDev debugger is shows that the VTable for
    the m object is invalid (i.e. "Expression cannot be evaluated" or some
    such method). The exception is *not* propagating out of main.
     
    , Jul 16, 2007
    #4
  5. Guest

    On Jul 15, 8:20 pm, Kai-Uwe Bux <> wrote:
    > wrote:
    > > I was wondering if someone could explain the output I am getting for
    > > the program below. What I expected from the main program output was
    > > "Cat" but instead I see "Mammal". The output is also included below.
    > > I got the same results with GCC 3.4.4 under cygwin as with MSDev
    > > studio 2003. Even stranger to me, if I change the catch statement to
    > > catch a Cat instead of a Mammal, the program crashes in the catch
    > > body, during the call to m.MyType(). Thanks for any explanations in
    > > advance.

    >
    > > Program:

    >
    > > #include <iostream>
    > > using namespace std;

    >
    > > class Mammal
    > > {
    > > public:
    > > Mammal()
    > > {
    > > cout << "Constructing Mammal @ " << this << endl;
    > > }
    > > Mammal(const Mammal& source)
    > > {
    > > cout << "Copy Constructing Mammal @ " << this << " from " <<
    > > &source << endl;
    > > }
    > > ~Mammal()
    > > {
    > > cout << "Destructing Mammal @ " << this << endl;
    > > }
    > > virtual const char* MyType()
    > > {
    > > return "Mammal";
    > > }
    > > };
    > > class Cat : public Mammal
    > > {
    > > public:
    > > Cat()
    > > {
    > > cout << "Constructing Cat @ " << this << endl;
    > > }
    > > Cat(const Cat& source)
    > > {
    > > cout << "Copy Constructing Cat @ " << this << " from " <<
    > > &source << endl;
    > > }
    > > ~Cat()
    > > {
    > > cout << "Destructing Cat @ " << this << endl;
    > > }

    >
    > > virtual const char* MyType()
    > > {
    > > return "Cat";
    > > }
    > > };

    >
    > > int main(int argc, char *argv[])
    > > {
    > > Cat fluffy;
    > > Mammal &fluffyRef = fluffy;
    > > try
    > > {
    > > throw fluffyRef;

    >
    > You throw a Mamal. At this point, a temporary Mamal is created and
    > initialized from fluffyRef, which involves slicing. See [15.1/3]:
    >
    > A throw-expression initializes a temporary object, called the exception
    > object, the type of which is determined by removing any top-level
    > cv-qualifiers from the static type of the operand of throw and adjusting
    > the type from ?array of T? or ?function returning T? to ?pointer to T?
    > or ?pointer to function returning T?, respectively.
    >
    > Note that the _static type_ is used for the temporary.
    >
    > Also note that a temporary copy is needed since the original is a local
    > object that has to go down during stack unwinding.
    >
    > > }
    > > catch (Mammal &m)

    >
    > At this point, the temporary implicitly created in the throw() is used to
    > initialize the Mamal& here. Since slicing already happened, you don't get a
    > Cat.
    >
    >
    >
    > > {
    > > cout << "Caught a " << m.MyType() << endl;
    > > return 0;
    > > }
    > > cout << "Nothing Caught" << endl;
    > > return 0;
    > > }

    >
    > > Output:

    >
    > > Steve@nessus /cygdrive/f/dev/src/TestWorkspace
    > > $ ./TestWorkspace.exe
    > > Constructing Mammal @ 0x22ccc0
    > > Constructing Cat @ 0x22ccc0
    > > Copy Constructing Mammal @ 0xc306d8 from 0x22ccc0
    > > Caught a Mammal
    > > Destructing Mammal @ 0xc306d8
    > > Destructing Cat @ 0x22ccc0
    > > Destructing Mammal @ 0x22ccc0

    >
    > Best
    >
    > Kai-Uwe Bux


    Ok I think I am understanding now - and my last post was not entirely,
    correct - I see now. Thanks for your quick responses.
     
    , Jul 16, 2007
    #5
  6. * :
    >> It would, yes, because the exception is then not caught and propagates
    >> out of "main".
    >>
    >>> in the catch
    >>> body, during the call to m.MyType().

    >> This I believe is a hypothesis of yours, and an incorrect one.

    >
    > Nope - I verified this with a debugger. The MSDev debugger crashed on
    > the call m.MyType(), and in cygwin I got the cout just prior to the
    > call and not the one after it.
    >
    > Also - looking with the MSDev debugger is shows that the VTable for
    > the m object is invalid (i.e. "Expression cannot be evaluated" or some
    > such method). The exception is *not* propagating out of main.


    Could theoreticalle happen because you have Undefined Behavior where
    anything can happen (in principle), but my guess is you debugged
    something that wasn't what you described.

    --
    A: Because it messes up the order in which people normally read text.
    Q: Why is it such a bad thing?
    A: Top-posting.
    Q: What is the most annoying thing on usenet and in e-mail?
     
    Alf P. Steinbach, Jul 16, 2007
    #6
  7. BobR Guest

    <> wrote in message...
    > I was wondering if someone could explain the output I am getting for
    > the program below. What I expected from the main program output was
    > "Cat" but instead I see "Mammal". The output is also included below.
    > I got the same results with GCC 3.4.4 under cygwin as with MSDev
    > studio 2003. Even stranger to me, if I change the catch statement to
    > catch a Cat instead of a Mammal, the program crashes in the catch
    > body, during the call to m.MyType(). Thanks for any explanations in
    > advance.
    > Program:
    >
    > #include <iostream>
    > using namespace std;


    class Mammal{ public:
    Mammal(){
    cout<<"Constructing Mammal @ "<<this<<std::endl;
    }
    Mammal( Mammal const &source ){
    cout<<"Copy Constructing Mammal @ "<<this
    <<" from "<<&source<<std::endl;
    }

    // ~Mammal(){
    // [Warning] class Mammal' has virtual functions but
    // non-virtual destructor
    // [Warning]`class Cat' has virtual functions but
    // non-virtual destructor

    virtual ~Mammal(){ // this quiets both warnings
    cout<<"Destructing Mammal @ "<<this<<std::endl;
    }
    virtual const char* MyType(){
    return "Mammal";
    }
    };
    // no change to Cat
    class Cat : public Mammal{ public:
    Cat(){
    cout<<"Constructing Cat @ "<<this<<std::endl;
    }
    Cat( Cat const &source ){
    cout<<"Copy Constructing Cat @ "<<this
    <<" from "<<&source<<std::endl;
    }
    ~Cat(){
    cout<<"Destructing Cat @ "<<this<<std::endl;
    }
    virtual const char* MyType(){
    return "Cat";
    }
    };
    >
    > int main(int argc, char *argv[]){
    > Cat fluffy;
    > Mammal &fluffyRef = fluffy;
    > try{


    throw fluffyRef; // to get 'Mammal' (a sliced 'Cat')
    // out: Copy Constructing Mammal @ 0xc5fb80
    // from 0xacee04 (Cat fluffy)

    // throw fluffy; // to get 'Cat'
    // Copy Constructing Cat @ 0xc5fb80 from 0xacee04

    > }

    // add:
    catch( Cat const &m ){
    cout<<"Caught a "<<m.MyType()<<std::endl;
    return EXIT_FAILURE;
    }

    > catch( Mammal &m ){
    > cout << "Caught a " << m.MyType() << endl;
    > return 0;
    > }


    // add:
    catch( ... ){ // that's 3 dots (not a placeholder)
    cout<<"Caught something, maybe the flu!"<<std::endl;
    return EXIT_FAILURE;
    }

    > cout << "Nothing Caught" << endl;
    > return 0;
    > }


    [ I'm not positive, this is my guess. ]
    Your 'fluffyRef' is a ref to 'Mammal'. If you only caught 'Cat &c' (and not
    'Mammal'), the program will exhibit an "un-caught exception" and terminate
    which looks like a crash).

    try{
    throw fluffy;
    }
    // catch( Cat &m ){
    // cout<<"Caught a "<<m.MyType()<<std::endl;
    // }
    catch( Mammal &m ){
    cout<<"Caught a "<<m.MyType()<<std::endl;
    Cat *cat = dynamic_cast<Cat*>( &m );
    if( cat ){ cout<<"It's a Cat!!"<<std::endl;}
    }
    // out: Caught a Cat
    // out: It's a Cat!!

    throw fluffyRef;
    // out: Caught a Mammal
    // The cast fails, which I think is slicing the Cat (at throw).

    --
    Bob R
    POVrookie
     
    BobR, Jul 16, 2007
    #7
  8. Guest Guest

    You can not expect polymorphism works in the try/catch idiom.
    As the Holy Standard illustrates:

    A throw-expression initializes a temporary object, called the
    exception object, the type of which is determined by removing any top-
    level cv-qualifiers from the static type of the operand of throw.[1]

    For the solution of this problem, you can go to http://www.ddj.com/dept/cpp/184401940.



    1.[1] ISO/IEC 14882:2003(E), "Programming Languages-C++," 15.1 63 and
    "How do I throw polymorphically?" C++ FAQ Lite,
    http://www.parashift.com/c -faq-lite/exceptions.html#faq-17.10.
     
    Guest, Jul 16, 2007
    #8
    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. Kerri
    Replies:
    2
    Views:
    13,090
    Kevin Spencer
    Oct 27, 2003
  2. Jon Maz
    Replies:
    7
    Views:
    4,332
    Jon Maz
    Oct 25, 2004
  3. Matt
    Replies:
    1
    Views:
    422
    Michael Rauscher
    Jun 12, 2004
  4. Replies:
    15
    Views:
    7,706
    Roedy Green
    Sep 8, 2005
  5. Chris Riesbeck

    try-catch-throw-finally

    Chris Riesbeck, Jan 19, 2007, in forum: Java
    Replies:
    3
    Views:
    1,055
    Chris Riesbeck
    Jan 22, 2007
Loading...

Share This Page