 |
C++Talk.NET C++ language newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
andrew_nuss@yahoo.com Guest
|
Posted: Sun May 13, 2007 8:01 am Post subject: when does exception destructor fire |
|
|
Hi,
Lets say we define a class to be used as an exception. Should it
extend std::exception or not? Either way, my question concerns the
case where the exception object is responsible for holding memory and
freeing it, like the following:
class MyException {
std::string msg;
public:
MyException (char const* str) : msg(str) {}
std::string GetMsg () const { return msg; }
};
When we have code that does:
....
char temp[256];
... // fill temp with sprintf()
throw MyException(temp);
Where on the stack does thrown MyException live? When does it go out
of scope? When does the destructor for MyException "fire", causing
its std::string data member to be destroyed? I mean, where does the
compiler put the exception object. By the way, is there any harm in
GetMsg() above returning a const reference?
Thanks,
Andy
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ] |
|
| Back to top |
|
 |
Salt_Peter Guest
|
Posted: Sun May 13, 2007 6:34 pm Post subject: Re: when does exception destructor fire |
|
|
{ Edits: quoted signature and clc++m banner removed. Tip: most
newsreader programs remove the clc++m banner automatically. -mod }
On May 13, 4:01 am, "andrew_n...@yahoo.com" <andrew_n...@yahoo.com>
wrote:
| Quote: | Hi,
Lets say we define a class to be used as an exception. Should it
extend std::exception or not?
|
Thats not required, You can throw/catch anything you like or need.
However, you might consider not using a std::string member (in case
the exception is one involving a lack of resources available, etc).
| Quote: | Either way, my question concerns the
case where the exception object is responsible for holding memory and
freeing it, like the following:
class MyException {
std::string msg;
public:
MyException (char const* str) : msg(str) {}
std::string GetMsg () const { return msg; }
};
|
In the case you plan to store a 'msg': use the facilities already
provided for you in std::exception and derivatives. As an example:
#include <iostream>
#include <stdexcept>
class MyException : std::runtime_error
{
public:
MyException() : std::runtime_error("unspecified") { }
MyException(const char* p) : std::runtime_error(p) { }
};
int main()
{
try {
throw MyException("testing...");
}
catch( const std::exception& r_e )
{
std::cout << "Error: " << r_e.what();
std::cout << std::endl;
}
}
/*
Error: testing...
*/
See member function what() in std::exception base class and note the
virtual dtor.
The following are all derived from std::exception (thats not a
complete list):
std::bad_alloc
std::bad_cast
std::bad_typeid
std::logic_error
std::runtime_error
std::bad_exception
Of those, both logic_error and runtime_error are perfect for your
needs.
The advantage is that a single catch block is needed.
| Quote: |
When we have code that does:
....
char temp[256];
... // fill temp with sprintf()
throw MyException(temp);
Where on the stack does thrown MyException live? When does it go out
of scope? When does the destructor for MyException "fire", causing
its std::string data member to be destroyed? I mean, where does the
compiler put the exception object. By the way, is there any harm in
GetMsg() above returning a const reference?
|
See the other responses here.
They'll do a far better job than i explaining those topics.
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ] |
|
| Back to top |
|
 |
Alf P. Steinbach Guest
|
Posted: Sun May 13, 2007 11:11 pm Post subject: Re: when does exception destructor fire |
|
|
* andrew_nuss (AT) yahoo (DOT) com:
| Quote: |
Lets say we define a class to be used as an exception. Should it
extend std::exception or not?
|
Depends whether it's intended to be caught by code that catches
std::exception, or not.
There are (as far as I know) three possible conventions for
differentiating between "hard" and "soft" exceptions, where the hard
ones are the ones that should always cause termination, i.e. should
always be rethrown if caught, always propagated, but possibly after
cleanup. (1) std::runtime_error versus std::exception, which treats
standard exceptions such as std::bad_alloc as hard, but is almost
impossible to enforce in other than toy programs, (2) anything else
versus std::exception, which just relies on never using a generic
catch(...) without rethrowing, and otherwise only catching
std::exception and derived classes, and (3) not having any hard
exceptions, but instead always terminate directly where there could
otherwise be a choice between direct termination and hard exception,
which I think is the most common convention and is the convention you're
subscribing to if the term "hard" exception appears to be meaningless.
For conventions 2 and 3, always derive from std::runtime_error (just
ignore arguments that premature optimization is a good idea, that the
possibility of a small disaster in the middle of a great one is worth a
lot to avoid, and the like: these arguments have been made). For
convention 1, which is rather unreliable, derive from std::runtime_error
for soft exceptions and directly from std::exception or from some other
class derived from std::exception for hard exceptions.
| Quote: | Either way, my question concerns the
case where the exception object is responsible for holding memory and
freeing it, like the following:
class MyException {
std::string msg;
public:
MyException (char const* str) : msg(str) {}
std::string GetMsg () const { return msg; }
};
When we have code that does:
....
char temp[256];
... // fill temp with sprintf()
throw MyException(temp);
Where on the stack does thrown MyException live?
|
The exception object is copied, via the copy constructor, somewhere
(although the compiler is permitted to optimize away this copying).
The copy is destroyed when the exception has been handled, i.e. on exit
from a catch that doesn't rethrow.
Note: the copying means that C++ exceptions are thrown "by value". To
achieve polymorphic rethrowing of a caught and stored exception object,
e.g. for propagation through C code, you need virtual clone and throw
member functions.
| Quote: | When does it go out
of scope?
|
Conventional C++ scope is the wrong concept here. For the copy, it's a
kind of dynamic scope, not a lexical scope.
| Quote: | When does the destructor for MyException "fire", causing
its std::string data member to be destroyed? I mean, where does the
compiler put the exception object.
|
See above.
| Quote: | By the way, is there any harm in
GetMsg() above returning a const reference?
|
Yes. It forces an implementation with a string member. But the
efficiency + convenience may weight up for that. Regarding efficiency
it may be better to use some string holder class that can propagate
literals without making a dynamically allocated copy.
Hth.,
- Alf, 13.05.2007 11:20
--
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?
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ] |
|
| Back to top |
|
 |
Alberto Ganesh Barbati Guest
|
Posted: Mon May 14, 2007 8:11 am Post subject: Re: when does exception destructor fire |
|
|
andrew_nuss (AT) yahoo (DOT) com ha scritto:
| Quote: | On May 13, 9:01 am, Alberto Ganesh Barbati <AlbertoBarb...@libero.it
wrote:
Question is: why do you ask? You shouldn't bother. If you don't do
anything fancy, the compiler will just do the right thing for you.
Anyway, as you are curious, let me say that the Standard is deliberately
vague in order to allow different implementation strategies. For
example, one possible strategy might be this:
1) the exception object is constructed in the stack of the throwing function
2) the catch handler that will catch the exception is determined
3) the exception object is copied in the stack in the catch handler
4) control flows is transferred to the catch handler. In this phase
stack unrolling happens, in particular every local object in the
throwing function *including* the original exception object are destroyed
5) the catch handler is executed
6) once the control flow leaves the catch handler (for whatever reason)
the copy of the exception object is destroyed
|
I have to apologize. It seems that the standard is clearer than I
thought and that the strategy I exposed in the previous message is not
allowed. The key paragraph is 15.1/4:
"The memory for the temporary copy of the exception being thrown is
allocated in an unspecified way, except as noted in 3.7.3.1. The
temporary persists as long as there is a handler being executed for that
exception. [...] When the last handler being executed for the exception
exits by any means other than throw; the temporary object is destroyed
and the implementation may deallocate the memory for the temporary
object; any such deallocation is done in an unspecified way. [...]"
So it seems that if you catch the object by reference, no copy of the
thrown object will be made.
| Quote: |
My Exception objects hold JNI jobject localrefs, and delete the
references in the destructor. Your strategy item #3 implies that I
must implement a copy constructor and an assignment operator doesn't
it. Why? Because otherwise the destructor fires twice in #4 and #6
against the same jni localref.
|
If your class holds references or pointers to anything, it is *always*
good programming practice to have proper copy-constructor and assignment
operator. Even you think you don't need them, do write them. Period.
Alternatively, mark the class as non-copyable by declaring private
copy-ctor and assignment, but never, never, NEVER write such a class
without them (and I mean *both* of them). The compiler can silently do
copies in so many places that you definitely want to have control over
it. Forgetting a "&" can happen, so don't rely on that!
HTH,
Ganesh
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ] |
|
| Back to top |
|
 |
Roman.Perepelitsa@gmail.c Guest
|
Posted: Mon May 14, 2007 9:10 am Post subject: Re: when does exception destructor fire |
|
|
On May 14, 12:11 pm, Alberto Ganesh Barbati <AlbertoBarb...@libero.it>
wrote:
| Quote: | "The memory for the temporary copy of the exception being thrown is
allocated in an unspecified way, except as noted in 3.7.3.1. The
temporary persists as long as there is a handler being executed for that
exception. [...] When the last handler being executed for the exception
exits by any means other than throw; the temporary object is destroyed
and the implementation may deallocate the memory for the temporary
object; any such deallocation is done in an unspecified way. [...]"
So it seems that if you catch the object by reference, no copy of the
thrown object will be made.
|
You have to define copy constructor for any object you throw. Notice
"The memory for the temporary copy of the exception being thrown..."
in 15.1/4. That is temprorary copy which is thrown. "throw" always
creates copy of the exception and throws it.
Roman Perepelitsa.
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ] |
|
| Back to top |
|
 |
|
|
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
|
|