By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
435,089 Members | 2,226 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 435,089 IT Pros & Developers. It's quick & easy.

Troubles with exception::what()

P: n/a
The following simple program behaves differently
in Windows and Linux .

#include <stdexcept>
#include <iostream>
#include <string>
using namespace std;
class LogicError : public logic_error {
public:
string desc;
explicit LogicError(string desc)
: logic_error("parent description"), desc(desc) {
}
virtual const char * what() const throw() {
return desc.c_str();
}
};
void f() {
throw LogicError("child description");
}
int main() {
try {
f();
} catch(exception e) {
cout << "e.what=[" << e.what() << "]" << endl;
}
try {
f();
} catch(exception & e) {
cout << "e.what=[" << e.what() << "]" << endl;
}
return 0;
}

When I run it on Windows (Visual Studio 6.0) I obtain:
e.what=[]
e.what=[child description]

When I run it on Windows (Visual Studio 7.1) I obtain:
e.what=[Unknown exception]
e.what=[child description]

On Linux I (obtain:
e.what=[9exception]
e.what=[child description]

Two questions to the C++ gurus:
<1> Which is the expected ANSI-C++ behaviour?
<2> Why. in each run, the first output row
is different from the second one?

Thanks for the help.

- Dario

Jul 19 '05 #1
Share this Question
Share on Google+
12 Replies


P: n/a
Dario wrote:
The following simple program behaves differently
in Windows and Linux .
#include <stdexcept>
#include <iostream>
#include <string>
using namespace std;
class LogicError : public logic_error {
public:
string desc;
explicit LogicError(string desc)
: logic_error("parent description"), desc(desc) {
}
virtual const char * what() const throw() {
return desc.c_str();
}
This is overriding the base "what" method.

Incidently, gcc 3.3.1 needed this:

~LogicError() throw() {};

It seems to make sense since the destructor of the base class also
specified throw().
};
void f() {
throw LogicError("child description");
}
int main() {
try {
f();
} catch(exception e) {
Exception caught by value - a copy of "exception" is made here.

Well this means that you're not using the method what above.

cout << "e.what=[" << e.what() << "]" << endl;
}
try {
f();
} catch(exception & e) {
Exception caught by reference - cool, now you will get the right what
becuase you are actually using a LogicError object and not an
"exception" object copied.
cout << "e.what=[" << e.what() << "]" << endl;
}
return 0;
}

When I run it on Windows (Visual Studio 6.0) I obtain:
e.what=[]
e.what=[child description]

When I run it on Windows (Visual Studio 7.1) I obtain:
e.what=[Unknown exception]
e.what=[child description]

On Linux I (obtain:
e.what=[9exception]
e.what=[child description]

Two questions to the C++ gurus:
<1> Which is the expected ANSI-C++ behaviour?
All of them. What happens on the first catch is undefined.
<2> Why. in each run, the first output row
is different from the second one?
Because they are different objects.

Thanks for the help.


Jul 19 '05 #2

P: n/a
On 26 Sep 2003 04:47:25 GMT, Gianni Mariani <gi*******@mariani.ws>
wrote:
Dario wrote:
The following simple program behaves differently
in Windows and Linux .
#include <stdexcept>
#include <iostream>
#include <string>
using namespace std;
BTW, one shouldn't ever put "using namespace ...<anything>" in a
header file... for toy programs such as this, it is probably OK.
class LogicError : public logic_error {
public:
string desc;
explicit LogicError(string desc)
: logic_error("parent description"), desc(desc) {
}
virtual const char * what() const throw() {
return desc.c_str();
}


He also should have a *virtual* destructor. It might be a better idea
to derive the class from std::exception and not from one of its
derived classes because not every implementation of the STL uses a
virtual destructor in the derived classes. In some of them, it will
work; in others, maybe not.

This is overriding the base "what" method.

Incidently, gcc 3.3.1 needed this:

~LogicError() throw() {};

It seems to make sense since the destructor of the base class also
specified throw().
};
void f() {
throw LogicError("child description");
}
int main() {
try {
f();
} catch(exception e) {


Exception caught by value - a copy of "exception" is made here.

Well this means that you're not using the method what above.

cout << "e.what=[" << e.what() << "]" << endl;
}
try {
f();
} catch(exception & e) {


Exception caught by reference - cool, now you will get the right what
becuase you are actually using a LogicError object and not an
"exception" object copied.
cout << "e.what=[" << e.what() << "]" << endl;
}
return 0;
}

When I run it on Windows (Visual Studio 6.0) I obtain:
e.what=[]
e.what=[child description]

When I run it on Windows (Visual Studio 7.1) I obtain:
e.what=[Unknown exception]
e.what=[child description]

On Linux I (obtain:
e.what=[9exception]
e.what=[child description]

Two questions to the C++ gurus:
<1> Which is the expected ANSI-C++ behaviour?


All of them. What happens on the first catch is undefined.
<2> Why. in each run, the first output row
is different from the second one?


Because they are different objects.

Thanks for the help.


--
Bob Hairgrove
rh**************@Pleasebigfoot.com
Jul 19 '05 #3

P: n/a
In article <3f**************@news.webshuttle.ch>,
rh*****************@EMailAddressbigfoot.com says...

[ ... ]
#include <stdexcept>
#include <iostream>
#include <string>
using namespace std;

BTW, one shouldn't ever put "using namespace ...<anything>" in a
header file...


....at namespace scope. Something like this:

#include <iostream>

class X {
using namespace std;

// declarations including "ostream" instead of "std::ostream".
};

is perfectly reasonable. The using declaration follows scope rules, so
after the end of the declaration of 'X', the using declaration no longer
has any effect.

[ ... ]
He also should have a *virtual* destructor.
He does. He's deriving indirectly from class exception, which is
required to have a virtual destructor ($18.6.1). Since its destructor
is virtual, the destructors of all derived classes are also virtual
($12.4/7). Since he hasn't declared a dtor explicitly, it's declared
implicitly ($12.4/3). Since he hasn't defined it explicitly either, it
will be defined implicitly ($12.4/5).
It might be a better idea
to derive the class from std::exception and not from one of its
derived classes because not every implementation of the STL uses a
virtual destructor in the derived classes. In some of them, it will
work; in others, maybe not.


If the base class destructor is virtual, the destructors of _all_
derived classes are virtual. This is an absolute requirement of the
language, and does not depend on the implementation of the standard
library -- any compiler that makes a derived dtor non-virtual when the
base dtor is virtual is simply _horribly_ broken -- to the point that I
don't think it's worth discussing in the context of C++ at all.

--
Later,
Jerry.

The universe is a figment of its own imagination.
Jul 19 '05 #4

P: n/a

"Dario" <da***@despammed.com> wrote in message news:bk**********@fata.cs.interbusiness.it...
} catch(exception e) {
cout << "e.what=[" << e.what() << "]" << endl;
}
When I run it on Windows (Visual Studio 6.0) I obtain:

e.what=[]
e.what=[child description]

When I run it on Windows (Visual Studio 7.1) I obtain:
e.what=[Unknown exception]
e.what=[child description]


This is to be expected. In the first try/catch you have slice your
thrown exception into an "exception". The dynamic type and
static type of e are the same. So in this case whatever implementation
defined string exception::what() prints is what you get.

In your second try/catch, you catch byreferece, therefore e still has
it's dynamic type of LogicError. The virtual what() function then
runs LogicError::what().
Jul 19 '05 #5

P: n/a

"Bob Hairgrove" <rh*****************@EMailAddressbigfoot.com> wrote in message news:3f**************@news.webshuttle.ch...

He also should have a *virtual* destructor.


The destructor is already virtual. std::exception's destructor is virtual so all
of it's children also have virtual destructors.
Jul 19 '05 #6

P: n/a
The following simple program behaves differently
in Windows and Linux .

#include <stdexcept>
#include <iostream>
#include <string>
using namespace std;
class LogicError : public logic_error {
public:
string desc;
explicit LogicError(string desc)
: logic_error("parent description"), desc(desc) {
}
virtual const char * what() const throw() {
return desc.c_str();
}
};
void f() {
throw LogicError("child description");
}
int main() {
try {
f();
} catch(exception e) {
cout << "e.what=[" << e.what() << "]" << endl;
}
try {
f();
} catch(exception & e) {
cout << "e.what=[" << e.what() << "]" << endl;
}
return 0;
}

When I run it on Windows (Visual Studio 6.0) I obtain:
e.what=[]
e.what=[child description]

When I run it on Windows (Visual Studio 7.1) I obtain:
e.what=[Unknown exception]
e.what=[child description]

On Linux I (obtain:
e.what=[9exception]
e.what=[child description]

Two questions to the C++ gurus:
<1> Which is the expected ANSI-C++ behaviour?
<2> Why. in each run, the first output row
is different from the second one?

Thanks for the help.

- Dario


No-one is able to give me an help ?

- Dario

Jul 19 '05 #7

P: n/a
Dario wrote:

....
Thanks for the help.

- Dario

No-one is able to give me an help ?


There were posts from Ron N. and myself. What's the issue ?

Jul 19 '05 #8

P: n/a
Bob Hairgrove wrote:
BTW, one shouldn't ever put "using namespace ...<anything>" in a
header file... for toy programs such as this, it is probably OK.
I use "using namespace ...<anything>" only in my *.cpp files.
He also should have a *virtual* destructor.
Yes, in my "actual" code I have it.
It might be a better idea to derive the class from std::exception and not from one of its
derived classes because not every implementation of the STL uses a
virtual destructor in the derived classes. In some of them, it will
work; in others, maybe not.


But my LogicError is a logic_error and not a generic exception.
So I will continue to derive from logic_error.
Incidently, gcc 3.3.1 needed this:

~LogicError() throw() {};

It seems to make sense since the destructor of the base class also
specified throw().
OK.
void f() {
throw LogicError("child description");
}
int main() {
try {
f();
} catch(exception e) {


Exception caught by value - a copy of "exception" is made here.

Well this means that you're not using the method what above.
cout << "e.what=[" << e.what() << "]" << endl;
}
try {
f();
} catch(exception & e) {


Exception caught by reference - cool, now you will get the right what
becuase you are actually using a LogicError object and not an
"exception" object copied.
OK.
Two questions to the C++ gurus:
<1> Which is the expected ANSI-C++ behaviour?


All of them. What happens on the first catch is undefined.
OK. Understood.
<2> Why. in each run, the first output row
is different from the second one?


Because they are different objects.


OK. Understood.

Thanks.

- Dario

Jul 19 '05 #9

P: n/a

"Dario" <da***@despammed.com> wrote in message news:bk**********@grillo.cs.interbusiness.it...

No-one is able to give me an help ?

I thought I did. Maybe we misunderstood your question.
The program behaves as expected. When you convert a derived class (LogicError)
a base class (exception), the object you create is the base class (exception). It's
not polymorphic, it is the base class initialzed with pieces of your derived class.

The reason it behaves differently between Linux an WIndows, is that exception::what()
returns diferent things on those machines. If you wrote:

int main() {
exception e;
cout << e.what() << endl;
}

and ran it on both machiens, you'd get the same thing you see for your first print in your
program. The standard just says the string is "implementation defined." In the case of
VC++ 6.0 it appears to just be an empty string. In VC++ 7 it is "unkonwn exception".
On Linux, it's "exception." All of these are technically correct.

When you use a reference to the base class instead, you have a polymorphic reference
to the derived object with the static type of the base class. In this case, the virtual function
what() returns your "child description."

Does this help? If not, you'll have to ask a more detailed question and we'll be glad to
explain further.

-Ron
Jul 19 '05 #10

P: n/a
On Fri, 26 Sep 2003 11:17:22 -0400, "Ron Natalie" <ro*@sensor.com>
wrote:

"Bob Hairgrove" <rh*****************@EMailAddressbigfoot.com> wrote in message news:3f**************@news.webshuttle.ch...

He also should have a *virtual* destructor.


The destructor is already virtual. std::exception's destructor is virtual so all
of it's children also have virtual destructors.


He is deriving his class from std::logic_error, not std::exception. We
had problems deriving from std::invalid_argument when we ported an
application from BCB5 using RogueWave STL to BCB6 using STLPort. It
wouldn't compile because STLPort's implementation of
std::invalid_argument does not have a virtual destructor (our class
did). At least, that was the error message we received. I assumed that
std::logic_error might suffer under the same symptom. Now, maybe
STLPort is broken? I don't know what the standard says, but I know
that we had problems because of the different implementations of the
STL, and that is why I gave that pieve of advice.
--
Bob Hairgrove
rh**************@Pleasebigfoot.com
Jul 19 '05 #11

P: n/a
Bob Hairgrove wrote:
He is deriving his class from std::logic_error, not std::exception. We
had problems deriving from std::invalid_argument when we ported an
application from BCB5 using RogueWave STL to BCB6 using STLPort. It
wouldn't compile because STLPort's implementation of
std::invalid_argument does not have a virtual destructor (our class
did). At least, that was the error message we received. I assumed that
std::logic_error might suffer under the same symptom. Now, maybe
STLPort is broken? I don't know what the standard says,

<snip>

10.3 Virtual functions [class.virtual]

2 If a virtual member function vf is declared in a class Base and in a
class Derived, derived directly or indirectly from Base, a member
function vf with the same name and same parameter list as Base::vf is
declared, then Derived::vf is also virtual (whether or not it is so
declared)

-Kevin
--
My email address is valid, but changes periodically.
To contact me please use the address from a recent posting.

Jul 19 '05 #12

P: n/a

"Bob Hairgrove" <rh*****************@EMailAddressbigfoot.com> wrote in message news:3f**************@news.webshuttle.ch...
The destructor is already virtual. std::exception's destructor is virtual so all
of it's children also have virtual destructors.

He is deriving his class from std::logic_error, not std::exception.


And logic_error is dervied from exeception. As I said, std::exception
and EVERYTHING DERIVED FROM IT has a virtual destructor.
We
had problems deriving from std::invalid_argument when we ported an
application from BCB5 using RogueWave STL to BCB6 using STLPort. It
wouldn't compile because STLPort's implementation of
std::invalid_argument does not have a virtual destructor (our class
did).


Something else is wrong. All of these classes are derived from a class
with a virtual destructor. That makes their destructors virtual. If you had
problems, it was because something was seriously wrokng with your impelemntation.
Jul 19 '05 #13

This discussion thread is closed

Replies have been disabled for this discussion.