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

S

stevewilliams2004

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
 
A

Alf P. Steinbach

* (e-mail address removed):
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
 
K

Kai-Uwe Bux

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
 
S

stevewilliams2004

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


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.
 
S

stevewilliams2004

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.

#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;
}

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.
 
A

Alf P. Steinbach

* (e-mail address removed):
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.
 
B

BobR

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).
 
G

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.
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,483
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top