From 4d05c28f669670d6d8ba4a551d8e4dd2e963efb1 Mon Sep 17 00:00:00 2001 From: Matthias Maier Date: Wed, 20 Nov 2013 10:31:09 +0000 Subject: [PATCH] Cleanup ExceptionBase: Inherit from std::exception and do the c_string handling directly to avoid the const_casts git-svn-id: https://svn.dealii.org/trunk@31723 0785d39b-7218-0410-832d-ea1e28bc413d --- deal.II/include/deal.II/base/exceptions.h | 14 ++-- deal.II/source/base/exceptions.cc | 86 +++++++++++++---------- 2 files changed, 56 insertions(+), 44 deletions(-) diff --git a/deal.II/include/deal.II/base/exceptions.h b/deal.II/include/deal.II/base/exceptions.h index 0f5f4c393d..8c5efbd859 100644 --- a/deal.II/include/deal.II/base/exceptions.h +++ b/deal.II/include/deal.II/base/exceptions.h @@ -24,7 +24,7 @@ #include -#include +#include #include #include @@ -43,7 +43,7 @@ DEAL_II_NAMESPACE_OPEN * @ingroup Exceptions * @author Wolfgang Bangerth, 1997, 1998, Matthias Maier, 2013 */ -class ExceptionBase : public std::runtime_error +class ExceptionBase : public std::exception { public: /** @@ -147,11 +147,15 @@ protected: 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; }; diff --git a/deal.II/source/base/exceptions.cc b/deal.II/source/base/exceptions.cc index 590f1ce1f6..22278be947 100644 --- a/deal.II/source/base/exceptions.cc +++ b/deal.II/source/base/exceptions.cc @@ -62,31 +62,28 @@ namespace deal_II_exceptions 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() {} @@ -98,6 +95,11 @@ ExceptionBase::~ExceptionBase () throw () free (stacktrace); stacktrace = 0; } + if (what_str != 0) + { + delete[] what_str; + what_str = 0; + } } @@ -128,26 +130,24 @@ void ExceptionBase::set_fields (const char *f, #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(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; } @@ -281,35 +281,43 @@ void ExceptionBase::print_stack_trace (std::ostream &out) const 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(this); - const_cast(*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... + } } -- 2.39.5