const char *cond,
const char *exc_name);
+
+ /**
+ * Override the standard function that returns the description of the error.
+ */
+ virtual const char* what() const throw();
+
/**
* Get exception name.
*/
* A backtrace to the position where the problem happened, if the
* system supports this.
*/
- char **stacktrace;
+ mutable char **stacktrace;
/**
* The number of stacktrace frames that are stored in the previous
*/
int n_stacktrace_frames;
+#ifdef HAVE_GLIBC_STACKTRACE
+ /**
+ * array of pointers that contains the raw stack trace
+ */
+ void *raw_stacktrace[25];
+#endif
+
private:
/**
* Internal function that generates the c_string that gets printed by
* exception::what(). Called by the ExceptionBase constructor and
* set_fields.
*/
- void generate_message();
+ void generate_message() const;
};
exc = e;
// If the system supports this, get a stacktrace how we got here:
-
if (stacktrace != 0)
{
free (stacktrace);
stacktrace = 0;
}
+ // Note that we defer the symbol lookup done by backtrace_symbols()
+ // to when we need it (see what() below). This is for performance
+ // reasons, as this requires loading libraries and can take in the
+ // order of seconds on some machines.
#ifdef HAVE_GLIBC_STACKTRACE
- void *array[25];
- n_stacktrace_frames = backtrace(array, 25);
- stacktrace = backtrace_symbols(array, n_stacktrace_frames);
+ n_stacktrace_frames = backtrace(raw_stacktrace, 25);
#endif
- // And finally populate the underlying std::runtime_error:
- generate_message();
+ // set the message to the empty string so that what() will compute
+ // a new error message with the new information.
+ std::runtime_error * base = static_cast<std::runtime_error *>(this);
+ *base = std::runtime_error("");
}
+const char* ExceptionBase::what() const throw()
+{
+ // We override the what() function to be able to look up the symbols
+ // of the stack trace.
+ if (std::runtime_error::what()[0]=='\0')
+ {
+#ifdef HAVE_GLIBC_STACKTRACE
+ stacktrace = backtrace_symbols(raw_stacktrace, n_stacktrace_frames);
+#endif
+
+ generate_message();
+ }
+ return std::runtime_error::what();
+}
const char *ExceptionBase::get_exc_name () const
-void ExceptionBase::generate_message ()
+void ExceptionBase::generate_message () const
{
// build up a string with the error message...
converter << "--------------------------------------------------------"
<< std::endl;
- // ... and set up std::runtime_error with it:
- static_cast<std::runtime_error &>(*this) = std::runtime_error(converter.str());
+ // ... and set up std::runtime_error with it. We need to do a const
+ // cast so we can change the what message even though our method is const.
+ const std::runtime_error * base = static_cast<const std::runtime_error *>(this);
+ const_cast<std::runtime_error &>(*base) = std::runtime_error(converter.str());
}