#include <deal.II/base/config.h>
-#include <stdexcept>
+#include <exception>
#include <string>
#include <ostream>
* @ingroup Exceptions
* @author Wolfgang Bangerth, 1997, 1998, Matthias Maier, 2013
*/
-class ExceptionBase : public std::runtime_error
+class ExceptionBase : public std::exception
{
public:
/**
private:
/**
- * Internal function that generates the c_string that gets printed by
- * exception::what(). Called by the ExceptionBase constructor and
- * set_fields.
+ * Internal function that generates the c_string. Called by what().
*/
void generate_message() const;
+
+ /**
+ * A pointer to the c_string that will be printed by what(). It is
+ * populated by generate_message()
+ */
+ mutable char* what_str;
};
ExceptionBase::ExceptionBase ()
:
- std::runtime_error(""),
file(""),
line(0),
function(""),
cond(""),
exc(""),
stacktrace (0),
- n_stacktrace_frames (0)
-{
- // Construct a minimalistic error message:
- generate_message();
-}
+ n_stacktrace_frames (0),
+ what_str(0)
+{}
ExceptionBase::ExceptionBase (const ExceptionBase &exc)
:
- std::runtime_error (exc),
file(exc.file),
line(exc.line),
function(exc.function),
cond(exc.cond),
exc(exc.exc),
stacktrace (0), // don't copy stacktrace to avoid double de-allocation problem
- n_stacktrace_frames (0)
+ n_stacktrace_frames (0),
+ what_str(0) // don't copy the error message, it gets generated dynamically by what()
{}
free (stacktrace);
stacktrace = 0;
}
+ if (what_str != 0)
+ {
+ delete[] what_str;
+ what_str = 0;
+ }
}
#ifdef HAVE_GLIBC_STACKTRACE
n_stacktrace_frames = backtrace(raw_stacktrace, 25);
#endif
-
- // 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')
+ // If no error c_string was generated so far, do it now:
+ if (what_str == 0)
{
#ifdef HAVE_GLIBC_STACKTRACE
+ // We have deferred the symbol lookup to this point to avoid costly
+ // runtime penalties due to linkage of external libraries by
+ // backtrace_symbols.
stacktrace = backtrace_symbols(raw_stacktrace, n_stacktrace_frames);
#endif
generate_message();
}
- return std::runtime_error::what();
+
+ return what_str;
}
void ExceptionBase::generate_message () const
{
- // build up a string with the error message...
+ // build up a c_string with the error message.
+ // Guard this procedure with a try block, we shall not throw at this
+ // place...
+ try
+ {
+ std::ostringstream converter;
- std::ostringstream converter;
+ converter << std::endl
+ << "--------------------------------------------------------"
+ << std::endl;
- converter << std::endl
- << "--------------------------------------------------------"
- << std::endl;
+ // print out general data
+ print_exc_data (converter);
+ // print out exception specific data
+ print_info (converter);
+ print_stack_trace (converter);
- // print out general data
- print_exc_data (converter);
- // print out exception specific data
- print_info (converter);
- print_stack_trace (converter);
+ if (!deal_II_exceptions::additional_assert_output.empty())
+ {
+ converter << "--------------------------------------------------------"
+ << std::endl
+ << deal_II_exceptions::additional_assert_output
+ << std::endl;
+ }
- if (!deal_II_exceptions::additional_assert_output.empty())
- {
converter << "--------------------------------------------------------"
- << std::endl
- << deal_II_exceptions::additional_assert_output
<< std::endl;
- }
- converter << "--------------------------------------------------------"
- << std::endl;
-
- // ... 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());
+ if (what_str != 0)
+ delete[] what_str;
+ what_str = new char[converter.str().size()+1]; // beware of the terminating \0 character
+ strcpy(what_str, converter.str().c_str());
+ }
+ catch (...)
+ {
+ // On error, resume next. There is nothing better we can do...
+ }
}