C++Talk.NET Forum Index C++Talk.NET
C++ language newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Re: Class Derived from std::exception.
Goto page 1, 2  Next
 
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated)
View previous topic :: View next topic  
Author Message
Ron Natalie
Guest





PostPosted: Sat Sep 13, 2003 8:20 am    Post subject: Re: Class Derived from std::exception. Reply with quote




"Isaac Rodriguez" <isaac.rodriguez (AT) autodesk (DOT) com> wrote

Quote:
virtual const char* what () const
{
return message().c_str();
}

The return value of c_str() is invalid once the string is destroyed which

it is shortly after you call it.

You're returning garbage.



[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Thomas Tutone
Guest





PostPosted: Sat Sep 13, 2003 8:24 am    Post subject: Re: Class Derived from std::exception. Reply with quote



"Isaac Rodriguez" wrote:

Quote:
#include #include #include
// My exception class.
//
class WinError : public std::exception
{
public:

WinError (int nCode) { mCode = nCode; }

virtual const char* what () const

I'm not sure if this is your only problem, but the
above line has the wrong function signature.
std::exception declares that member function as:

virtual const char* what() const throw();

You left off the the "throw()" at the end. When I
fixed that problem, your program seemed to work OK on
gcc 3.3. Actually, that's not quite true - my
compiler had some problems parsing the parentheses you
put around the very last throw expression. That seems
to be a problem with GCC, but I'm curious - why do you
include them? In other words, why not just say "throw
x" instead of "throw (x)"?

Best regards,

Tom


















__________________________________
Do you Yahoo!?
Yahoo! SiteBuilder - Free, easy-to-use web site design software
http://sitebuilder.yahoo.com

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Ulrich Eckhardt
Guest





PostPosted: Sat Sep 13, 2003 8:26 am    Post subject: Re: Class Derived from std::exception. Reply with quote



Isaac Rodriguez wrote:
Quote:
class WinError : public std::exception
virtual const char* what () const
{
return message().c_str();
}

Here, I see two problems: the first is that the correct declaration would
be
virtual char const* what() const throw();
The other problem is that the temporary that message() returns goes out of
scope but you still return a pointer to its buffer.

Two suggestions here:
1. return a char const* from message()
2. derive from e.g. std::runtime_error which has an internal buffer that
does not get destroyed

Quote:
catch (WinError& err) {

why not 'catch( WinError const& e)' ?

Uli

--
Questions ?
see C++-FAQ Lite: http://parashift.com/c++-faq-lite/ first !


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Siemel Naran
Guest





PostPosted: Sat Sep 13, 2003 8:35 am    Post subject: Re: Class Derived from std::exception. Reply with quote

"Isaac Rodriguez" <isaac.rodriguez (AT) autodesk (DOT) com> wrote in message

Quote:
class WinError : public std::exception
{
public:

WinError (int nCode) { mCode = nCode; }

virtual const char* what () const
{
return message().c_str();
}

std::string message () const
{
std::string strMsg;
if (mCode == 1) {

strMsg = "File not found";
}
else if (mCode == 2) {

strMsg = "Invalid handle";

}
else {
strMsg = "Unknown error";
}

return strMsg;
}

After message() is done, the local variable strMsg is destroyed. But it
returns a newly constructed string, which the calling function may or may
not choose to save in a variable. So far OK. Now let's look at the calling
function --

Quote:
virtual const char* what () const
{
return message().c_str();
}

The call to message() create a temporary string as noted above. This
temporary string is not stored or assigned to a variable as in

std::string variable = message();

so it gets destroyed automatically at the end of the statement, or in other
words at the semicolon.

The call to .c_str() gets a pointer to the C representation of the string,
and so far it's valid. If you were to call another function like
strcmp("a", message().c_str()) then it woud be valid. However you just
return this c_str pointer. Unfortunately at the semicolon the string is
destroyed and therefore the returned c_str pointer is invalid.


Quote:
The problem that I am having is that when I catch a WinError exception as
a
std::exception and call what(), although the debugger steps to the
WinError
overloaded function, the result that I get on the screen is garbage.

This code was implemented and run using VC7.0 and I didn't try any other
compilers since I don't have them available right now.

Your compiler is right to print garbage. The string has been deleted, and
the memory the pointer points to can be used for other purposes. On many
platforms (including some Windows platforms and UNIX/Linux), the program
will crash.

May I suggest the following rewrite

class WinError : public std::exception
{
public:

enum ErrorCode { FILE_NOT_FOUND=1, INVALID_HANDLE, UNKNOWN_ERROR };
explicit WinError (ErrorCode nCode) { mCode = nCode; }

virtual const char* what () const
{
switch (mCode) {
case FILE_NOT_FOUND: return "File not found";
case INVALID_HANDLE: return "Invalid handle";
default: return "Unknown error";
}
}

private:

ErrorCode mCode;

};


Another design is to derive a new class for each error. For example,

class WinError : public std::exception { ... };
class WinFileError : public WinError { ... };
class WinFileNotFound : public WinFileError { ... };
class WinFileInvalidHandle : public WinFileError { ... };

--
+++++++++++
Siemel Naran


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Shay
Guest





PostPosted: Sat Sep 13, 2003 7:54 pm    Post subject: Re: Class Derived from std::exception. Reply with quote

Ulrich Eckhardt wrote:
Quote:
Isaac Rodriguez wrote:
[snip]
catch (WinError& err) {

why not 'catch( WinError const& e)' ?

I've encountered so many bugs with exception handling that I wouldn't
tempt a compiler's runtime with a reference-to-const in an exception
handler. This is a case where I can do without the safety offered by const
(exception types are usually very simple anyway).

--
Shay

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Nicolas Fleury
Guest





PostPosted: Mon Sep 15, 2003 9:56 am    Post subject: Re: Class Derived from std::exception. Reply with quote

Isaac Rodriguez wrote:
Quote:
virtual const char* what () const
{
return message().c_str();
}

Different solutions have been proposed to correct the problem you have
using a temporary string. In your specific example, using a switch with
const strings like Siemel proposed is fine, but if your real example
contains more complex and dynamic strings, a solution is to simply put
your "message" as a member, assuming you will not need the string
outside of the catch.

Regards,

Nicolas

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Ulrich Eckhardt
Guest





PostPosted: Mon Sep 15, 2003 3:38 pm    Post subject: Re: Class Derived from std::exception. Reply with quote

Shay wrote:
Quote:
Ulrich Eckhardt wrote:
Isaac Rodriguez wrote:
catch (WinError& err) {

why not 'catch( WinError const& e)' ?

I've encountered so many bugs with exception handling that I wouldn't
tempt a compiler's runtime with a reference-to-const in an exception
handler.

Can you give concrete compiler/version/age where that did not work ?

Uli


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
kanze@gabi-soft.fr
Guest





PostPosted: Mon Sep 15, 2003 10:05 pm    Post subject: Re: Class Derived from std::exception. Reply with quote

Ulrich Eckhardt <doomster (AT) knuut (DOT) de> wrote

Quote:
Isaac Rodriguez wrote:
class WinError : public std::exception
virtual const char* what () const
{
return message().c_str();
}

Here, I see two problems: the first is that the correct declaration
would be
virtual char const* what() const throw();
The other problem is that the temporary that message() returns goes
out of scope but you still return a pointer to its buffer.

Two suggestions here:
1. return a char const* from message()

But won't this only move the problem? The problem is that he wants to
dynamically generate a string and then return a char const* into the
string. As far as I know, it can't be done; you need to store the
string somewhere for the char const* to continue to be valid.

In his case, the obvious solution is to add a string attribute to the
class. This attribute could be either filled in completely in the
constructor, or some sort of lazy evaluation could be used, e.g.:

char const*
WinError::what() const
{
if ( myMessage == "" ) {
myMessage = message() ;
}
return myMessage.c_str() ;
}

Quote:
2. derive from e.g. std::runtime_error which has an internal buffer
that does not get destroyed

It may be true that deriving from std::runtime_error is a good idea, but
I don't see where it has an accessible internal buffer. He'd have to
calculate the actual string used before calling the constructor --
something along the lines of:

WinError::WinError( ... )
: std::runtime_error( message( ... ) )
{
}

where message is a static function which takes the necessary parameters
and returns the necessary string.

--
James Kanze GABI Software mailto:kanze (AT) gabi-soft (DOT) fr
Conseils en informatique orientée objet/ http://www.gabi-soft.fr
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France, +33 (0)1 30 23 45 16

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Dave L. Delaney
Guest





PostPosted: Tue Sep 16, 2003 6:42 am    Post subject: Re: Class Derived from std::exception. Reply with quote

On Fri, 12 Sep 2003 17:31:45 -0400, Isaac Rodriguez wrote:


Quote:
Hi,

I've run into a problem the other day, so I took the time to write a small
program that will reproduce the problem in order to see if any of you can
tell me what is going on.

This is the code...


void test_my_exception ()
{
try {

throw_my_exception();
}
catch (WinError& err) {

std::cout << "Message: " << err.message() << std::endl
"What: " << err.what() << std::endl;
}

try {
throw_my_exception();
}
catch (std::exception& err) {

std::cout << "What: " << err.what() << std::endl;
}
}

Try creating the exception on the heap.

throw ( new WinError(1));

then change the catch statement to work with pointers. (polymorphism in C++ is done with pointers.)

Catch( std:exception* err){
std::cout << err->what() << std::endl.
}

This works with gcc v3.3 and VC V6.

Hope this helps.


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Ulrich Eckhardt
Guest





PostPosted: Tue Sep 16, 2003 8:38 pm    Post subject: Re: Class Derived from std::exception. Reply with quote

Dave L. Delaney wrote:
Quote:
throw ( new WinError(1));

catch( std::exception* err){
std::cout << err->what() << std::endl;
}

This works with gcc v3.3 and VC V6.

Yes, and it leaks memory.
This is a non-solution, IMHO.

Uli


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Siemel Naran
Guest





PostPosted: Wed Sep 17, 2003 9:18 am    Post subject: Re: Class Derived from std::exception. Reply with quote

"Ulrich Eckhardt" <doomster (AT) knuut (DOT) de> wrote

Quote:
Dave L. Delaney wrote:

throw ( new WinError(1));

catch( std::exception* err){
std::cout << err->what() << std::endl;
}

This works with gcc v3.3 and VC V6.

Yes, and it leaks memory.
This is a non-solution, IMHO.

But it's leading to a good solution. Throw a smart pointer like
boost::shared_ptr
--
+++++++++++
Siemel Naran


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Ulrich Eckhardt
Guest





PostPosted: Wed Sep 17, 2003 8:17 pm    Post subject: Re: Class Derived from std::exception. Reply with quote

Siemel Naran wrote:
Quote:
"Ulrich Eckhardt" <doomster (AT) knuut (DOT) de> wrote:
Dave L. Delaney wrote:
throw ( new WinError(1));

catch( std::exception* err){
std::cout << err->what() << std::endl;
}

Yes, and it leaks memory.
This is a non-solution, IMHO.

But it's leading to a good solution. Throw a smart pointer like
boost::shared_ptr

That way, you have two dynamic allocations[1] which is a hell of a lot of
overhead for an exception - they already have a reputation for being slow,
no reason to add to that.

Even worse, consider this:

try
{
throw boost::shared_ptr<std::exception>(new WinError(42));
}
catch(boost::shared_ptr<WinError> e)
{
x();
}
catch(boost::shared_ptr<std::exception> e)
{
y();
}

Which catch gets invoked? For sure not the one that the code seems to
suggest, no?

Am I missing something ?

Uli

[1] 'new WinError()' and the refcounter of boost::shared_ptr<>, assuming the
current i12n and that WinError is not derived from boost::shared_from_this
which makes it an intrusive refcounter.

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Aaron Bentley
Guest





PostPosted: Thu Sep 18, 2003 9:59 am    Post subject: Re: Class Derived from std::exception. Reply with quote

Siemel Naran wrote:

Quote:
"Ulrich Eckhardt" <doomster (AT) knuut (DOT) de> wrote in message
news:bk75ag$q8eke$1@ID-

Dave L. Delaney wrote:

This works with gcc v3.3 and VC V6.

Yes, and it leaks memory.
This is a non-solution, IMHO.


But it's leading to a good solution. Throw a smart pointer like
boost::shared_ptr<std::exception>.


Scot Meyers recommends catch-by-reference. This supports polymorphism
and doesn't leak memory. Is there a reason to use (smart) pointers instead?

Aaron

--
Aaron Bentley
www.aaronbentley.com

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Daniel Spangenberg
Guest





PostPosted: Fri Sep 19, 2003 10:18 am    Post subject: Re: Class Derived from std::exception. Reply with quote

Hello Aaron Bentley!

Aaron Bentley schrieb:

Quote:
Siemel Naran wrote:

"Ulrich Eckhardt" <doomster (AT) knuut (DOT) de> wrote in message
news:bk75ag$q8eke$1@ID-

Dave L. Delaney wrote:

This works with gcc v3.3 and VC V6.

Yes, and it leaks memory.
This is a non-solution, IMHO.


But it's leading to a good solution. Throw a smart pointer like
boost::shared_ptr<std::exception>.


Scot Meyers recommends catch-by-reference. This supports polymorphism
and doesn't leak memory. Is there a reason to use (smart) pointers instead?

Aaron

Some months ago, we had a similar discussion. You might want to have a look at
the rather long thread with the title "strings in exceptions?" beginning with

http://groups.google.de/groups?q=g:thl1331788373d&dq=&hl=de&lr=&ie=UTF-8&selm=roy-E12386.13425702072003%40reader1.panix.com

The main problems of exceptions objects is the following: On the one side they
have to guarantee a no-throw copy-c'tor, on the other hand they often transport
data items which might throw during their copy process.

There are two obvious solutions from this dilemma, provided you will not
restrict
the types of information items inside the exception object:

1) Prevent that these data items are actually copied. One solution is the usage
of reference-counted data items. Although not every reference-counting
scheme provides a no-throw guarantee (Sometimes the counter itself has to be
allocated), they are possible.

2) Instead of transporting one exception object with a bunch of handles on its
data items you could theoretically transport the handle of one exception object
(e.g. via boost::shared_ptr<ExceptionType>) which contains its data items
by value or not. Unfortuneatly this ansatz also has some disadvantages, noteably

the fact that catching derived exceptions by their base classes is practically
impossible, as David Abrahams has pointed out.

Greetings from Bremen,

Daniel


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
kanze@gabi-soft.fr
Guest





PostPosted: Fri Sep 19, 2003 10:20 am    Post subject: Re: Class Derived from std::exception. Reply with quote

Ulrich Eckhardt <doomster (AT) knuut (DOT) de> wrote


Quote:
Siemel Naran wrote:
"Ulrich Eckhardt" <doomster (AT) knuut (DOT) de> wrote:
Dave L. Delaney wrote:
throw ( new WinError(1));

catch( std::exception* err){
std::cout << err->what() << std::endl;
}

Yes, and it leaks memory. This is a non-solution, IMHO.

But it's leading to a good solution. Throw a smart pointer like
boost::shared_ptr
That way, you have two dynamic allocations[1] which is a hell of a lot
of overhead for an exception - they already have a reputation for
being slow, no reason to add to that.

Big deal. Handling an exception can easily cost 100 times the cost of
an allocation. Or more. You aren't going to be able to measure the
difference.

On the other hand, while the original suggestion of using pointers might
have leaked memory, it didn't do anything to solve the original
problem. Making the pointers intelligent fixes this, but what is the
point in patching up a solution which doesn't fix any problem to begin
with. And of course, using smart pointers has the problem you pointed
out -- a catch ( Base* ) will catch a Derived*, but a
catch< smart_ptr< Base > won't catch a smart_ptr< Derved > -- as far as
the type system is concerned, smart_ptr< Base > and smart_ptr< Derived >
are two completely independant types.

--
James Kanze GABI Software mailto:kanze (AT) gabi-soft (DOT) fr
Conseils en informatique orientée objet/ http://www.gabi-soft.fr
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France, +33 (0)1 30 23 45 16

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Display posts from previous:   
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated) All times are GMT
Goto page 1, 2  Next
Page 1 of 2

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.