|
|
|
|
|
|
| |
| |
|
|
|
|
| |
| |
|
|
Nicolas Alvarez wrote:
> Darren New wrote:
>> Nicolas Alvarez wrote:
>>> Darren New wrote:
>>>> I wasn't aware C++ even defined tracebacks on exceptions.
>>> It doesn't.
>> Then the traceback in your exceptions can't tell you the values, can it?
>
> Exceptions have no "traceback" directly visible at runtime from inside the
> code.
That's what I was saying.
> You can use platform-specific code in an exception handler to get a
> stack trace (by following stack pointers).
And that's what I asked - what would I google on to see this, given it's not
defined in exception.h? What's it called?
> When an application crashes, the crash handler *attaches* a debugger to the
> just-segfaulted app, loads the debugging symbols from a different file,
> gets a stacktrace, and lets the crashed app die and R.I.P.
Of course, it helps that it's crashing, instead of trying to actually do
something about the problem, I suppose. And that most systems will have a
debugger installed already.
--
Darren New, San Diego CA, USA (PST)
My fortune cookie said, "You will soon be
unable to read this, even at arm's length."
Post a reply to this message
|
|
| |
| |
|
|
|
|
| |
| |
|
|
Darren New wrote:
> And that's what I asked - what would I google on to see this, given it's
> not defined in exception.h? What's it called?
It's not directly related to exceptions, since it's a C API (not C++).
GNU libc (not libstdc++!) has C functions to get backtraces at any moment.
It's a GNU extension. You may very well call it in an exception handler.
http://www.gnu.org/software/libtool/manual/libc/Backtraces.html
The Windows API has similar functionality through the DlgHelp module,
especially the StackWalk64() and SymFromAddr() functions.
Post a reply to this message
|
|
| |
| |
|
|
|
|
| |
| |
|
|
Warp wrote:
> that objects could register themselves to some centralized, non-template
> factory, using their own typeid as key, so that the factory could create
> clones of those objects at runtime, based on those typeids.)
Actually, wouldn't this be clearer to do with virtual functions or pointers
to functions anyway? Where does typeid make things better in that scenario?
Isn't it just as easy to do something like
class Alpha : Beta {
....
virtual const char * me() { return "Alpha:Beta"; }
....
}
and switch on that? That even gives you a defined value, so you can (say)
write it into a file and read it back on the next run to reload objects that
serialized themselves or something. Plus, you avoid the overhead of putting
RTTI type_info on *every* class, most of which probably won't be registered
that way?
--
Darren New, San Diego CA, USA (PST)
My fortune cookie said, "You will soon be
unable to read this, even at arm's length."
Post a reply to this message
|
|
| |
| |
|
|
|
|
| |
| |
|
|
Darren New wrote:
> Warp wrote:
>> that objects could register themselves to some centralized, non-template
>> factory, using their own typeid as key, so that the factory could create
>> clones of those objects at runtime, based on those typeids.)
>
> Actually, wouldn't this be clearer to do with virtual functions or
> pointers to functions anyway? Where does typeid make things better in that
> scenario? Isn't it just as easy to do something like
>
> class Alpha : Beta {
> ....
> virtual const char * me() { return "Alpha:Beta"; }
> ....
> }
>
> and switch on that? That even gives you a defined value, so you can (say)
> write it into a file and read it back on the next run to reload objects
> that serialized themselves or something.
I think the most useful feature of RTTI is not typeid() to get a string, but
dynamic_cast.
void foo(Alpha* ptr) {
Beta* beta = dynamic_cast<Beta*>(ptr);
}
If ptr is a Beta object that was (maybe implicitly) cast to a Alpha*, then
beta is now equal to ptr (except its type is Beta*, so you can use Beta
members). If ptr actually pointed to an Alpha, or a Delta (another subclass
of Alpha), then the cast will throw a std::bad_cast exception.
In other words, dynamic_cast behaves like Java typecasts. We just call it
std::bad_cast instead of java.lang.ClassCastException.
Post a reply to this message
|
|
| |
| |
|
|
|
|
| |
| |
|
|
Nicolas Alvarez wrote:
> GNU libc (not libstdc++!) has C functions to get backtraces at any moment.
> It's a GNU extension. You may very well call it in an exception handler.
>
> http://www.gnu.org/software/libtool/manual/libc/Backtraces.html
It would seem that's rather not very useful in the exception handler? Or am
I misunderstanding? If I catch a division-by-zero in main() and I want to
log what function that happened in, how would I do that?
I guess what I'm asking is, isn't it the case that by the time you're in the
exception handler, the stack frames leading to the unexpected exception have
already been cleaned up, and all the stuff that's on the stack is working
correctly?
If I have a server, and I want to catch and log failures, in most languages
I do something along the lines of
main() {
try {
do_main_loop();
} except Exception e {
log("Uncaught exception", e);
} finally {
clean_up();
}
}
but by the time I get to the log() call, the stack is gone, yes? Where would
I put the call to "backtrace" such that I'd catch the actual function that
threw the exception?
--
Darren New, San Diego CA, USA (PST)
My fortune cookie said, "You will soon be
unable to read this, even at arm's length."
Post a reply to this message
|
|
| |
| |
|
|
|
|
| |
| |
|
|
Darren New wrote:
> Nicolas Alvarez wrote:
>> GNU libc (not libstdc++!) has C functions to get backtraces at any
>> moment. It's a GNU extension. You may very well call it in an exception
>> handler.
>>
>> http://www.gnu.org/software/libtool/manual/libc/Backtraces.html
>
> It would seem that's rather not very useful in the exception handler? Or
> am I misunderstanding? If I catch a division-by-zero in main() and I want
> to log what function that happened in, how would I do that?
Uh... Actually you're right :)
I dunno... I think you might be able to do something like this:
template<typename E>
void my_throw_exception(E& exc) {
//do the backtrace() dance and store the results somewhere in exc
throw exc;
}
But that's a bit cumbersome.
(PS: Division by zero doesn't throw a C++ exception)
Post a reply to this message
|
|
| |
| |
|
|
|
|
| |
| |
|
|
On Mon, 09 Mar 2009 00:33:32 +0100, Nicolas Alvarez
<nic### [at] gmailcom> wrote:
>
> void foo(Alpha* ptr) {
> Beta* beta = dynamic_cast<Beta*>(ptr);
> }
>
> If ptr is a Beta object that was (maybe implicitly) cast to a Alpha*,
> then
> beta is now equal to ptr (except its type is Beta*, so you can use Beta
> members). If ptr actually pointed to an Alpha, or a Delta (another
> subclass
> of Alpha), then the cast will throw a std::bad_cast exception.
No. A failed dynamic_cast of a pointer simply returns a null pointer. Only
failed casts of a reference result in a std::bad_cast exception.
--
FE
Post a reply to this message
|
|
| |
| |
|
|
|
|
| |
| |
|
|
"Fredrik Eriksson" <fe79}--at--{yahoo}--dot--{com> wrote:
> No. A failed dynamic_cast of a pointer simply returns a null pointer. Only
> failed casts of a reference result in a std::bad_cast exception.
Thanks for that. I first thought it returned null, but then I searched the
Internets and saw a try { ... } catch(std::bad_cast), so I thought I was
wrong. I didn't notice the difference was that the example I found used
references :)
Post a reply to this message
|
|
| |
| |
|
|
|
|
| |
| |
|
|
Nicolas Alvarez wrote:
> template<typename E>
> void my_throw_exception(E& exc) {
> //do the backtrace() dance and store the results somewhere in exc
> throw exc;
> }
And yes, you do need the template. The 'throw' statement uses the *static*
type of the variable. So for example:
class MyError: public std::exception {};
void my_throw_exception(std::exception& exc) {
throw exc;
}
void foo(int test) {
switch (test) {
case 1:
throw std::exception();
break;
case 2:
throw MyError();
break;
case 3:
my_throw_exception(std::exception());
break;
case 4:
my_throw_exception(MyError()); // <- MyError gets sliced here
break;
}
}
int main() {
try {
foo(1);
} catch(MyError& e) {
std::cerr << "MyError thrown\n";
} catch(std::exception& e) {
std::cerr << "std::exception thrown\n";
}
}
It will only print "MyError thrown" if you pass 2 to foo().
Post a reply to this message
|
|
| |
| |
|
|
|
|
| |
| |
|
|
Nicolas Alvarez wrote:
> I think the most useful feature of RTTI is not typeid() to get a string, but
> dynamic_cast.
Yeah, but I've never seen an OO language that lacks that feature. :-)
Singling it out as something with a special name seems odd to me. I guess
the C++ standards authors just like making up their own names for things. It
would be like saying "Our language supports class-based OOP *and* virtual
functions!"
Don't things like GCC support dynamic_cast and virtual functions this even
if you compile without the switch that enables typeid? (Or with the switch
that turns it off? I seem to be finding conflicting info, altho I might be
looking at different compilers.)
It seems strange, too, that it would add any overhead at all, except maybe
one word of pointer to each class's code, to point to the type_info object.
Don't you need vtable pointers even if "RTTI" is turned off?
--
Darren New, San Diego CA, USA (PST)
My fortune cookie said, "You will soon be
unable to read this, even at arm's length."
Post a reply to this message
|
|
| |
| |
|
|
|
|
| |