Guidelines for effective exception usage
Are there any guidelines on where and when to use exceptions? Are there any boost components that deal with exceptions? Stephen -- Email: storri@torri.org
"Stephen torri"
Are there any guidelines on where and when to use exceptions?
See http://www.boost.org/more/error_handling.html Jonathan
On Sun, 2004-08-22 at 23:41, Jonathan Turkanis wrote:
"Stephen torri"
wrote in message news:1093230456.8377.44.camel@base.torri.org... Are there any guidelines on where and when to use exceptions?
Thanks for the link. I had already found this link but was confused on some of advice it gave. The question below are some of my confusion about using exceptions wisely. What I am seeking for each of them is an example explaining how it implements a solution. 1) Use virutal inheritance. I see the example and can understand why its wrong I just do not understand how to fix it. 2) Don't embed a std::string ... How can I use the data I have at the point of the error safely? I want to provide a debug message to the user that will lead them to the answer. This affects 6) Expose relevant information about the cause of the error. In my project I have a base class called BaseException that inherits from std::exception. class BaseException : public std::exception { // virtual functions? virtual const char* what() const throw() = 0; }; I want exceptions in the code to be obvious to what is wrong but use the what() message to say why: class DataTypeException : public BaseException { DataTypeException (std::string msg) : Base_Exception(), m_msg(msg) {} // Specify virtual functions? virtual const char* what() const throw() { try { std::stringstream output; output << m_exception_name << ": " << m_message.c_str() << std::endl; return (output.str()).c_str(); } catch(std::exception &) { return m_exception_name; } } private: std::string m_msg; }; Stephen -- Email: storri@torri.org
"Stephen torri"
On Sun, 2004-08-22 at 23:41, Jonathan Turkanis wrote:
"Stephen torri"
wrote in message news:1093230456.8377.44.camel@base.torri.org... Are there any guidelines on where and when to use exceptions?
Thanks for the link. I had already found this link but was confused on some of advice it gave. The question below are some of my confusion about using exceptions wisely. What I am seeking for each of them is an example explaining how it implements a solution.
1) Use virutal inheritance. I see the example and can understand why its wrong I just do not understand how to fix it.
2) Don't embed a std::string ... How can I use the data I have at
I believe in the example the fix is to use virtual inheritance in the definitions of my_exc1 and my_exc2, so that later someone can derive from both. Using virtual inheritance in the definition of your_exc3 doen't help. I see that this advice is not followed consistently within boost (Robert Ramey's serialization library is the only case I can find). But it's still good advice, I think. the
point of the error safely? I want to provide a debug message to the user that will lead them to the answer. This affects 6) Expose relevant information about the cause of the error.
It's not always possible to satisfy condition (2), but you should do it whenever possible.
In my project I have a base class called BaseException that inherits from std::exception.
class DataTypeException : public BaseException { DataTypeException (std::string msg) : Base_Exception(), m_msg(msg) {}
// Specify virtual functions? virtual const char* what() const throw() { try { std::stringstream output; output << m_exception_name << ": " << m_message.c_str() << std::endl; return (output.str()).c_str(); } catch(std::exception &) { return m_exception_name; } } private:
std::string m_msg; };
Often you can get away with: class Data_Exception : public std::exception { public: Data_Exception(int code) : code_(code) { } virtual const char* what() const throw() { [return result of looking up code in a table of error messages.] } private: int code; }; As I said, this isn't always sufficient, but it often is. Jonathan
On Mon, 2004-08-23 at 15:04, Jonathan Turkanis wrote:
1) Use virutal inheritance. I see the example and can understand why its wrong I just do not understand how to fix it.
I believe in the example the fix is to use virtual inheritance in the definitions of my_exc1 and my_exc2, so that later someone can derive from both. Using virtual inheritance in the definition of your_exc3 doen't help. I see that this advice is not followed consistently within boost (Robert Ramey's serialization library is the only case I can find). But it's still good advice, I think.
To do virtual inheritance I was under the belief that the base class had only pure virtual methods. Each subclass then implements the virtual methods. Is this what was intended or am I misunderstanding the term virtual inheritance?
Often you can get away with:
class Data_Exception : public std::exception { public: Data_Exception(int code) : code_(code) { } virtual const char* what() const throw() { [return result of looking up code in a table of error messages.] } private: int code; };
So each class has a predefined table of int/string pairs. This table should be a static member of this class because there is not need to have multiple instances. Can you use a std::map or sgi hash_map to construct the table? Stephen -- Email: storri@torri.org
Stephen torri
On Mon, 2004-08-23 at 15:04, Jonathan Turkanis wrote:
1) Use virutal inheritance. I see the example and can understand why its wrong I just do not understand how to fix it.
I believe in the example the fix is to use virtual inheritance in the definitions of my_exc1 and my_exc2, so that later someone can derive from both. Using virtual inheritance in the definition of your_exc3 doen't help. I see that this advice is not followed consistently within boost (Robert Ramey's serialization library is the only case I can find). But it's still good advice, I think.
To do virtual inheritance I was under the belief that the base class had only pure virtual methods. Each subclass then implements the virtual methods. Is this what was intended or am I misunderstanding the term virtual inheritance?
It has nothing to do with virtual functions. struct my_exception : virtual std::exception ^^^^^^^ { // ... }; HTH, -- Dave Abrahams Boost Consulting http://www.boost-consulting.com
"Stephen torri"
To do virtual inheritance I was under the belief that the base class had only pure virtual methods. Each subclass then implements the virtual methods. Is this what was intended or am I misunderstanding the term virtual inheritance?
Yes. See http://tinyurl.com/5sgv8 [25.9].
Often you can get away with:
class Data_Exception : public std::exception { public: Data_Exception(int code) : code_(code) { } virtual const char* what() const throw() { [return result of looking up code in a table of error messages.] } private: int code; };
So each class has a predefined table of int/string pairs. This table should be a static member of this class because there is not need to have multiple instances.
Can you use a std::map or sgi hash_map to construct the table?
Yes. But if you constuct the table on first use, and the purpose of the table is partly to avoid running out of memory when constructing exceptions, it's probably better to use a built-in array.
Stephen
Jonathan
--- At Mon, 23 Aug 2004 15:48:47 -0400, Stephen torri wrote:
Can you use a std::map or sgi hash_map to construct the table?
This seems like an enormous hassle. Something has to build the table and that table will likely be mostly static (but I can see something being more dynamic.) Which brings me to my inquiry. I have struggled to work out how one might do a static map. I can lay one out in a table, but I would like it to work like a map. e.g struct useful_data_t { std::string useful_data; }; struct useful_data_map { int key; useful_data_t value; }; static useful_data_map[] = { { 1, { "useful data 1" } }, { 2, { "useful data 2" } } }; Now I would like to use this like a std::map or tr1::hash_map; Does boost have anything like this? Other suggestions? ...Duane
My two cents of the referenced html page. Not placing attributes like string into an exception class only makes sense if the exception being thrown has something to do with a memory starvation situation. For a lot of exception types that I can think of this is not the case. As an example of this std::runtime_error often has a string attribute and this is perfectly fine. Jonathan Turkanis wrote:
"Stephen torri"
wrote in message news:1093230456.8377.44.camel@base.torri.org... Are there any guidelines on where and when to use exceptions?
See http://www.boost.org/more/error_handling.html
Jonathan
_______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
Jeff Holle
My two cents of the referenced html page.
Not placing attributes like string into an exception class only makes sense if the exception being thrown has something to do with a memory starvation situation.
For a lot of exception types that I can think of this is not the case.
As an example of this std::runtime_error often has a string attribute and this is perfectly fine.
No it is not. Even if you aren't throwing due to memory starvation, you could run out of memory during unwinding, when the exception is copied. That leads you directly to terminate(). Do not pass Go; do not collect $200. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com
"David Abrahams"
Jeff Holle
writes:
No it is not. Even if you aren't throwing due to memory starvation, you could run out of memory during unwinding, when the exception is copied. That leads you directly to terminate(). Do not pass Go; do not collect $200.
So basically my advice is all wrong ? If you have to embed strings, make sure all allocation takes place at the time of construction, and use reference counting? Jonathan
"Jonathan Turkanis"
"David Abrahams"
wrote in message news:uu0utmv5h.fsf@boost-consulting.com... Jeff Holle
writes: No it is not. Even if you aren't throwing due to memory starvation, you could run out of memory during unwinding, when the exception is copied. That leads you directly to terminate(). Do not pass Go; do not collect $200.
So basically my advice is all wrong ?
?? I only said Jeff was wrong.
If you have to embed strings, make sure all allocation takes place at the time of construction, and use reference counting?
Yes, that's right. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com
"David Abrahams"
"Jonathan Turkanis"
writes: "David Abrahams"
wrote in message news:uu0utmv5h.fsf@boost-consulting.com... Jeff Holle
writes: No it is not. Even if you aren't throwing due to memory starvation, you could run out of memory during unwinding, when the exception is copied. That leads you directly to terminate(). Do not pass Go; do not collect $200.
So basically my advice is all wrong ?
?? I only said Jeff was wrong.
I don't remember why I phrased it that way. I didn't think your remarks were aimed at me.
If you have to embed strings, make sure all allocation takes place at the time of construction, and use reference counting?
Yes, that's right.
I remember looking at filesystem_error sometime back, and thinking 'if Beman does it, it must be okay'. ;-) But I see it's been fixed. Jonathan
At Monday 2004-08-23 13:55, you wrote:
Jeff Holle
writes: My two cents of the referenced html page.
Not placing attributes like string into an exception class only makes sense if the exception being thrown has something to do with a memory starvation situation.
For a lot of exception types that I can think of this is not the case.
As an example of this std::runtime_error often has a string attribute and this is perfectly fine.
No it is not. Even if you aren't throwing due to memory starvation, you could run out of memory during unwinding, when the exception is copied. That leads you directly to terminate(). Do not pass Go; do not collect $200.
why would unwinding copy the exception?
-- Dave Abrahams Boost Consulting http://www.boost-consulting.com
_______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
Victor A. Wagner Jr. http://rudbek.com The five most dangerous words in the English language: "There oughta be a law"
"Victor A. Wagner Jr."
At Monday 2004-08-23 13:55, you wrote:
Jeff Holle
writes: My two cents of the referenced html page.
Not placing attributes like string into an exception class only makes sense if the exception being thrown has something to do with a memory starvation situation.
For a lot of exception types that I can think of this is not the case.
As an example of this std::runtime_error often has a string attribute and this is perfectly fine.
No it is not. Even if you aren't throwing due to memory starvation, you could run out of memory during unwinding, when the exception is copied. That leads you directly to terminate(). Do not pass Go; do not collect $200.
why would unwinding copy the exception?
Because the language specification says it can. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com
At Tuesday 2004-08-24 00:39, you wrote:
"Victor A. Wagner Jr."
writes: At Monday 2004-08-23 13:55, you wrote:
Jeff Holle
writes: My two cents of the referenced html page.
Not placing attributes like string into an exception class only makes sense if the exception being thrown has something to do with a memory starvation situation.
For a lot of exception types that I can think of this is not the case.
As an example of this std::runtime_error often has a string attribute and this is perfectly fine.
No it is not. Even if you aren't throwing due to memory starvation, you could run out of memory during unwinding, when the exception is copied. That leads you directly to terminate(). Do not pass Go; do not collect $200.
why would unwinding copy the exception?
Because the language specification says it can.
you _can_ paint your face with green and red polka dots also. doesn't mean the rest of us won't or shouldn't ridicule those who do. Not to put TOO fine a point on it, but the entire raison dêtre of creating a language and libraries is to make is _easy_ for the user to write things.
-- Dave Abrahams Boost Consulting http://www.boost-consulting.com
Victor A. Wagner Jr. http://rudbek.com The five most dangerous words in the English language: "There oughta be a law"
"Victor A. Wagner Jr."
As an example of this std::runtime_error often has a string attribute and this is perfectly fine.
No it is not. Even if you aren't throwing due to memory starvation, you could run out of memory during unwinding, when the exception is copied. That leads you directly to terminate(). Do not pass Go; do not collect $200.
why would unwinding copy the exception?
Because the language specification says it can.
you _can_ paint your face with green and red polka dots also. doesn't mean the rest of us won't or shouldn't ridicule those who do.
Not to put TOO fine a point on it, but the entire raison dêtre of creating a language and libraries is to make is _easy_ for the user to write things.
Well I guess you didn't put a fine enough point on it, because I don't know what your point is. What's your point? -- Dave Abrahams Boost Consulting http://www.boost-consulting.com
At Tuesday 2004-08-24 09:58, you wrote:
"Victor A. Wagner Jr."
writes: As an example of this std::runtime_error often has a string attribute and this is perfectly fine.
No it is not. Even if you aren't throwing due to memory starvation, you could run out of memory during unwinding, when the exception is copied. That leads you directly to terminate(). Do not pass Go; do not collect $200.
why would unwinding copy the exception?
Because the language specification says it can.
you _can_ paint your face with green and red polka dots also. doesn't mean the rest of us won't or shouldn't ridicule those who do.
Not to put TOO fine a point on it, but the entire raison dêtre of creating a language and libraries is to make is _easy_ for the user to write things.
Well I guess you didn't put a fine enough point on it, because I don't know what your point is. What's your point?
OK, blunt point. the standard is (insert favorite expletive or "in error") if it allows use of std::runtime_error to terminate the program due to low memory situations (run out of memory (due to copying) during stack unwinding).
-- Dave Abrahams Boost Consulting http://www.boost-consulting.com
_______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
Victor A. Wagner Jr. http://rudbek.com The five most dangerous words in the English language: "There oughta be a law"
Victor A. Wagner Jr. wrote:
OK, blunt point. the standard is (insert favorite expletive or "in error") if it allows use of std::runtime_error to terminate the program due to low memory situations (run out of memory (due to copying) during stack unwinding).
It does not allow such a thing.
"Peter Dimov"
Victor A. Wagner Jr. wrote:
OK, blunt point. the standard is (insert favorite expletive or "in error") if it allows use of std::runtime_error to terminate the program due to low memory situations (run out of memory (due to copying) during stack unwinding).
It does not allow such a thing.
No? It seemed to me that it does, for perversely low QOI implementations. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com
"David Abrahams"
"Thorsten Ottosen"
"David Abrahams"
wrote in message news:u7jro6r4d.fsf@boost-consulting.com... | "Peter Dimov" writes: | | > Victor A. Wagner Jr. wrote: | >> OK, blunt point. | >> the standard is (insert favorite expletive or "in error") if it | >> allows use of std::runtime_error to terminate the program due to low | >> memory situations (run out of memory (due to copying) during stack | >> unwinding). | > | > It does not allow such a thing. | | No? It seemed to me that it does, for perversely low QOI | implementations. hm...funny. I talked with Matt Austern and Peter Becker about this in Sydney. They made me believe that if the copy-constrctor of a string throws in this line
throw std::run_time_error( "foo" );
then it wouldn't call terminate, but instead throw the wrong exception, namely (probably) a bad_alloc.
Is that a misunderstanding?
No, that's correct. In question was whether an exception can be thrown from within the run_time_error's copy ctor during unwinding, and whether that would cause termination. It's no longer clear to me that such an implementation would be legal. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com
On Aug 26, 2004, at 5:05 PM, David Abrahams wrote:
In question was whether an exception can be thrown from within the run_time_error's copy ctor during unwinding, and whether that would cause termination. It's no longer clear to me that such an implementation would be legal.
18.6.1 makes it clear that std::exception and all classes derived from it can not let an exception escape from their copy constructor. So if std::runtime_error's copy ctor throws, unexpected must be called, which will lead to termination. I suspect what was meant by the standard was that std::exception's copy ctor can't fail, and ditto for all classes derived from std::exception. And thus the need for a statically checked nothrow (or can't fail) spec. -Howard
At Tuesday 2004-08-24 14:39, you wrote:
Victor A. Wagner Jr. wrote:
OK, blunt point. the standard is (insert favorite expletive or "in error") if it allows use of std::runtime_error to terminate the program due to low memory situations (run out of memory (due to copying) during stack unwinding).
It does not allow such a thing.
Did I misunderstand Mr. Abrahams comment that started "No it is not"?
_______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
Victor A. Wagner Jr. http://rudbek.com The five most dangerous words in the English language: "There oughta be a law"
"Victor A. Wagner Jr."
At Tuesday 2004-08-24 09:58, you wrote:
"Victor A. Wagner Jr."
writes: the standard is (insert favorite expletive or "in error") if it allows use of std::runtime_error to terminate the program due to low memory situations (run out of memory (due to copying) during stack unwinding).
Well, that's up to QOI, really. Anything can happen due to violated "implementation limits". Further, there's no requirement that std::runtime_error contain a std::string by value. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com
Victor A. Wagner Jr. wrote:
At Monday 2004-08-23 13:55, you wrote:
Jeff Holle
writes: My two cents of the referenced html page.
Not placing attributes like string into an exception class only makes sense if the exception being thrown has something to do with a memory starvation situation.
For a lot of exception types that I can think of this is not the case. As an example of this std::runtime_error often has a string attribute and this is perfectly fine.
No it is not. Even if you aren't throwing due to memory starvation, you could run out of memory during unwinding, when the exception is copied. That leads you directly to terminate(). Do not pass Go; do not collect $200.
why would unwinding copy the exception?
The question isn't really about what happens in practice (where std::string members usually "work fine", although some implementations do use a proper reference-counted immutable string for std::runtime_error). It's mostly about "principles". Consider a hypothetical language (or tool) that can statically enforce throw() specifications. In such a language, you wouldn't be able to throw a type whose copy constructor is not marked throw(). Since std::string's copy constructor can throw, it can't be a member of a throwable class.
Hi everybody, I need to use the boost::call_once function defined on the boost/thread/once.hpp file. I need to pass 2 arguments to the function I call once but boost::call_once only takes void (*func)() as argument. Boost::bind won't help me here I think since what I need is not a functor. I need something that can be passed to call_once as a void (*func)() but where I can pass parameters. Anyway, any help on this would be greatly appreciated. Also, any other way to call a function once in a multithreaded environment just like boost::call_once does would work for me. Thanks -delfin
"Jeff Holle"
My two cents of the referenced html page.
Not placing attributes like string into an exception class only makes sense if the exception being thrown has something to do with a memory starvation situation.
If you run out of memory when you're trying to throw a non-memory related exception, you loose some information which might be helpful some of the time. So I'd say not embedding strings is a good rule of thumb. If you can't easily avoid it, don't worry, otherwise don't do it.
For a lot of exception types that I can think of this is not the case.
As an example of this std::runtime_error often has a string attribute and this is perfectly fine.
Sure. The standard library doesn't follow the boost guidelines. Jonathan
"Stephen torri"
Are there any guidelines on where and when to use exceptions? Are there any boost components that deal with exceptions?
Did anyone mention the article in the August issue of CUJ by Herb Sutter called "When and How to Use Exceptions"? Or do you mean boost-specific guidelines? // Johan
participants (11)
-
David Abrahams
-
Delfin Rojas
-
Duane Murphy
-
Howard Hinnant
-
Jeff Holle
-
Johan Nilsson
-
Jonathan Turkanis
-
Peter Dimov
-
Stephen torri
-
Thorsten Ottosen
-
Victor A. Wagner Jr.