From 44428dcbfa410120c498576f1db9ad413d318da1 Mon Sep 17 00:00:00 2001 From: Wolfgang Bangerth Date: Tue, 21 Feb 2006 03:08:50 +0000 Subject: [PATCH] Move most of the text found in the ExceptionBase class to the Exceptions doxygen module. git-svn-id: https://svn.dealii.org/trunk@12430 0785d39b-7218-0410-832d-ea1e28bc413d --- deal.II/base/include/base/exceptions.h | 290 +--------------------- deal.II/doc/doxygen/headers/exceptions.h | 293 ++++++++++++++++++++++- 2 files changed, 294 insertions(+), 289 deletions(-) diff --git a/deal.II/base/include/base/exceptions.h b/deal.II/base/include/base/exceptions.h index f007e71a77..dede4adc26 100644 --- a/deal.II/base/include/base/exceptions.h +++ b/deal.II/base/include/base/exceptions.h @@ -32,292 +32,16 @@ /** - * This class should be used as a base class for all exception - * classes. Do not use its methods and variables directly since the - * interface and mechanism may be subject to change. Rather create - * new exception classes using the DeclException macro - * family. - * - * - *

General overview of the exception handling mechanism in deal.II

- * - * The error handling mechanism in deal.II is generally used in two ways. - * The first uses error checking in debug mode only and is useful for programs - * which are not fully tested. When the program shows no error anymore, one may - * switch off error handling and get better performance by this, since checks - * for errors are done quite frequently in the library (a typical speed up is - * a factor of four!). This mode of exception generation is most useful for - * internal consistency checks such as range checking or checking of the - * validity of function arguments. Errors of this kind usually are programming - * errors and the program should abort with as detailed a message as possible, - * including location and reason for the generation of the exception. - * - * The second mode is for error checks which should always be on, such as for - * I/O errors, failing memory requests and the like. It does not make much - * sense to turn this mode off, since this kind of errors may happen in tested - * and untested programs likewise. Exceptions of this kind do not terminate the - * program, rather they throw exceptions in the C++ manner, allowing the - * program to catch them and eventually do something about it. As it may be - * useful to have some information printed out if an exception could not be - * handled properly, additional information is passed along as for the first - * mode. The latter makes it necessary to provide a family of macros which - * enter this additional information into the exception class; this could - * in principle be done by the programmer himself each time by hand, but since - * the information can be obtained automatically, a macro is provided for - * this. - * - * Both modes use exception classes, which need to have special features - * in additional to the C++ standard's exception class. Such a class - * is declared by the following lines of code: - * @code - * DeclException2 (ExcDomain, int, int, - * << "Index= " << arg1 << "Upper Bound= " << arg2); - * @endcode - * This declares an exception class named ExcDomain, which - * has two variables as additional information (named - * arg1 and arg2 by default) and which outputs the - * given sequence (which is appended to an std::ostream - * variable's name, thus the weird syntax). There are - * other DeclExceptionN macros for exception classes - * with more or no parameters. It is proposed to let start - * the name of all exceptions by Exc... and to declare them locally to - * the class it is to be used in. Declaring exceptions globally is possible - * but pollutes the global namespace, is less readable and thus unnecessary. - * - * Since exception classes are declared the same way for both modes of error - * checking, it is possible to use an exception declared through the - * DeclExceptionN(...) macro family in both modes; there is no need to - * declare different classes for each of these. - * - * - *

Use of the debug mode exceptions

- * - * To use the exception mechanism for debug mode error checking, write lines - * like the following in your source code: - * @code - * Assert (nDEBUG is set and if the given condition (in this case - * n < dim is violated). - * - * If the exception was declared using the DeclException0 (...) - * macro, i.e. without any additional parameters, its name has - * nonetheless to be given with parentheses: - * Assert (i>m, ExcSomewhat()); - * - *

How it works internally

- * - * If the DEBUG preprocessor directive is set, the call Assert - * (cond, exc); is basically converted by the preprocessor into the - * sequence (note that function names and exact calling sequences may - * change over time, but the general principle remains the same) - * @code - * if (!(cond)) - * deal_II_exceptions::internals::issue_error_assert_1 - * (__FILE__, - * __LINE__, - * __PRETTY_FUNCTION__, - * #cond, - * #exc, - * &exc); - * @endcode - * i.e. if the given condition is violated, then the file and - * line in which the exception occured as well as - * the condition itself and the call sequence of the - * exception object is transferred. Additionally an object - * of the form given by exc is created (this is normally an - * unnamed object like in ExcDomain (n, dim) of class - * ExcDomain) and transferred to the deal_II_exceptions::internals::issue_error_assert_1() - * function. - * - * __PRETTY__FUNCTION__ is a macro defined by some compilers and - * gives the name of the function. If another compiler is used, we - * try to set this function to something reasonable, if the compiler - * provides us with that, and "(not available)" otherwise. - * - * In __IssueError the given data is transferred into the - * exc object by calling the set_fields() function; after that, the - * general error info is printed onto std::cerr using the - * PrintError() function of exc and finally the exception specific - * data is printed using the user defined function PrintError() (which is - * normally created using the DeclException (...) macro family. If - * it can be obtained from the operating system, the output may also contain - * a stacktrace to show where the error happened. - * - * After printing all this information, - * deal_II_exceptions::internals::abort() is called (with one - * exception, see the end of this section). This terminates the - * program, which is the right thing to do for this kind of error - * checking since it is used to detect programming errors rather than - * run-time errors; a program can, by definition, not recover from - * programming errors. - * - * If the preprocessor variable DEBUG is not set, then nothing - * happens, i.e. the Assert macro is expanded to {}. - * - * Sometimes, there is no useful condition for an exception other - * than that the program flow should not have reached a certain point, - * e.g. a default section of a switch statement. In this case, - * raise the exception by the following construct: - * @verbatim - * Assert (false, ExcInternalError()); - * @endverbatim - * - * As mentioned above, the program is terminated once a call to - * Assert fails. However, there is one case where we do not want - * to do this, namely when a C++ exception is active. The usual case - * where this happens is that someone throws an exception through the - * AssertThrow mechanism (see below) which, while the stack is - * unwound, leads to the destruction of other objects in stack frames - * above. If other objects refer to the objects being thus destroyed, - * some destructors raise an exception through Assert. If we - * would abort the program then, we would only ever see the message - * that an object is being destroyed which is still referenced from - * somewhere, but we would never see the original exception that - * triggered this. (You can see it in the debugger by putting a break - * point on the function __throw, but you cannot see it from the - * program itself.) In that case, we use a C++ standard library - * function to detect the presence of another active exception and do - * not terminate the program to allow that the thrown exception - * propagates to some place where its message can be displayed. - * - * Since it is common that one failed assertion leads to a whole - * chain of others, we only ever print the very first message. If the - * program is then aborted, that is no problem. If it is not (since a - * C++ exception is active), only the first is displayed and a - * message about suppressed follow-up messages is shown. - * - * - *

Use of run-time exceptions

- * - * For this mode, the standard C++ throw and catch concept exists. We - * want to keep to this, but want to extend it a bit. In general, the - * structure is the same, i.e. you normally raise and exception by - * @code - * if (!(cond)) - * throw ExcSomething(); - * @endcode - * and catch it using the statement - * @code - * try { - * do_something (); - * } - * catch (exception &e) { - * std::cerr << "Exception occured:" << std::endl - * << e.what () - * << std::endl; - * do_something_to_reciver (); - * }; - * @endcode - * exception is a standard C++ class providing basic functionality for - * exceptions, such as the virtual function what() which returns some - * information on the exception itself. This information is useful if an - * exception can't be handled properly, in which case as precise a description - * as possible should be printed. - * - * The problem here is that to get significant and useful information out - * of what(), it is necessary to overload this function in out exception - * class and call the throw operator with additional arguments to the - * exception class. The first thing, overloading the what function is - * done using the DeclExceptionN macros, but putting the right information, - * which is the same as explained above for the Assert expansion, requires - * some work if one would want to write it down each time: - * @code - * if (!(cond)) - * { - * ExcSomething e(additional information); - * e.set_fields (__FILE__, __LINE__, __PRETTY_FUNCTION__, - * "condition as a string", - * "name of condition as a string"); - * throw e; - * }; - * @endcode - * - * For this purpose, the macro AssertThrow was invented. It does - * mainly the same job as does the Assert macro, but it does not - * kill the program, it rather throws an exception as shown above. The mode - * of usage is - * @code - * AssertThrow (cond, ExcSomething(additional information)); - * @endcode - * - * The condition to be checked is incorporated into the macro in order to - * allow passing the violated condition as a string. The expansion of the - * AssertThrow macro is not affected by the DEBUG - * preprocessor variable. - * - * - *

Description of the DeclExceptionN macro family

- * - * Declare an exception class without any additional parameters. - * There is a whole family of DeclException? macros - * where ? is to be replaced by the number of additional - * parameters (0 to 5 presently). - * - * The syntax is as follows: - * @code - * DeclException2 (ExcDomain, - * int, - * int, - * << " i=" << arg1 << ", m=" << arg2); - * @endcode - * The first is the name of the exception class to be created. - * The next arguments are the types of the parameters (in this - * case there are two type names needed) and finally the output - * sequence with which you can print additional information. - * - * The syntax of the output sequence is a bit weird but gets - * clear once you see how this macro is defined: - * @code - * class name : public ExceptionBase { - * public: - * name (const type1 a1, const type2 a2) : - * arg1 (a1), arg2(a2) {}; - * virtual void print_info (std::ostream &out) const { - * out outsequence << std::endl; - * }; - * private: - * type1 arg1; - * type2 arg2; - * }; - * @endcode - * - * If declared as specified, you can later use this exception class - * in the following manner: - * @code - * int i=5; - * int m=3; - * Assert (i of file . - * The violated condition was: - * iDeclException0(name) macro, no types and - * also no output sequence is allowed. + * This class is the base class for all exception classes. Do not use + * its methods and variables directly since the interface and + * mechanism may be subject to change. Rather create new exception + * classes using the DeclException macro family. * + * See the @ref Exceptions module for more details on this class and + * what can be done with classes derived from it. * * @ingroup Exceptions - * @author Wolfgang Bangerth, November 1997, extensions 1998 + * @author Wolfgang Bangerth, 1997, extensions 1998 */ class ExceptionBase : public std::exception { diff --git a/deal.II/doc/doxygen/headers/exceptions.h b/deal.II/doc/doxygen/headers/exceptions.h index 48d148a2a8..6dcf4e7647 100644 --- a/deal.II/doc/doxygen/headers/exceptions.h +++ b/deal.II/doc/doxygen/headers/exceptions.h @@ -15,8 +15,11 @@ * @defgroup Exceptions Exceptions and assertions * * This module contains classes that are used in the exception mechanism of - * deal.II. Exceptions are used in two different ways: + * deal.II. * + *

Brief overview

+ * + * Exceptions are used in two different ways: *
    * *
  • Static assertions: These are checks that are only enabled in debug @@ -47,13 +50,291 @@ * * Rather, one has to check them every time during execution of a * program. Within deal.II, this is done using the AssertThrow macro - * introduced in step-9, step-13, and following tutorial programs. The macro - * checks a condition, and if violated throws an exception of one of the - * types declared in this module, using the C++ throw - * mechanism. Since these are run-time exceptions, this gives the program - * the chance to catch the exception and, for example, write the output to a + * introduced in @ref step_9 "step-9", @ref step_13 "step-13", and + * following tutorial programs. The macro checks a condition, and if + * violated throws an exception of one of the types declared in this + * module, using the C++ throw mechanism. Since these + * are run-time exceptions, this gives the program the chance to + * catch the exception and, for example, write the output to a * writable file instead. *
+ * + * + *

Detailed description

+ * + * The error handling mechanism in deal.II is generally used in two ways. + * The first uses error checking in debug mode only and is useful for programs + * which are not fully tested. When the program shows no error anymore, one may + * switch off error handling and get better performance by this, since checks + * for errors are done quite frequently in the library (a typical speed up is + * a factor of four!). This mode of exception generation is most useful for + * internal consistency checks such as range checking or checking of the + * validity of function arguments. Errors of this kind usually are programming + * errors and the program should abort with as detailed a message as possible, + * including location and reason for the generation of the exception. + * + * The second mode is for error checks which should always be on, such as for + * I/O errors, failing memory requests and the like. It does not make much + * sense to turn this mode off, since this kind of errors may happen in tested + * and untested programs likewise. Exceptions of this kind do not terminate the + * program, rather they throw exceptions in the C++ manner, allowing the + * program to catch them and eventually do something about it. As it may be + * useful to have some information printed out if an exception could not be + * handled properly, additional information is passed along as for the first + * mode. The latter makes it necessary to provide a family of macros which + * enter this additional information into the exception class; this could + * in principle be done by the programmer himself each time by hand, but since + * the information can be obtained automatically, a macro is provided for + * this. + * + * Both modes use exception classes, which need to have special features + * in additional to the C++ standard's exception class. Such a class + * is declared by the following lines of code: + * @code + * DeclException2 (ExcDomain, int, int, + * << "Index= " << arg1 << "Upper Bound= " << arg2); + * @endcode + * This declares an exception class named ExcDomain, which + * has two variables as additional information (named + * arg1 and arg2 by default) and which outputs the + * given sequence (which is appended to an std::ostream + * variable's name, thus the weird syntax). There are + * other DeclExceptionN macros for exception classes + * with more or no parameters. It is proposed to let start + * the name of all exceptions by Exc... and to declare them locally to + * the class it is to be used in. Declaring exceptions globally is possible + * but pollutes the global namespace, is less readable and thus unnecessary. + * + * Since exception classes are declared the same way for both modes of error + * checking, it is possible to use an exception declared through the + * DeclExceptionN(...) macro family in both modes; there is no need to + * declare different classes for each of these. + * + * + *

Use of the debug mode exceptions

+ * + * To use the exception mechanism for debug mode error checking, write lines + * like the following in your source code: + * @code + * Assert (nDEBUG is set and if the given condition (in this case + * n < dim is violated). + * + * If the exception was declared using the DeclException0 (...) + * macro, i.e. without any additional parameters, its name has + * nonetheless to be given with parentheses: + * Assert (i>m, ExcSomewhat()); + * + *

How it works internally

+ * + * If the DEBUG preprocessor directive is set, the call Assert + * (cond, exc); is basically converted by the preprocessor into the + * sequence (note that function names and exact calling sequences may + * change over time, but the general principle remains the same) + * @code + * if (!(cond)) + * deal_II_exceptions::internals::issue_error_assert_1 + * (__FILE__, + * __LINE__, + * __PRETTY_FUNCTION__, + * #cond, + * #exc, + * &exc); + * @endcode + * i.e. if the given condition is violated, then the file and + * line in which the exception occured as well as + * the condition itself and the call sequence of the + * exception object is transferred. Additionally an object + * of the form given by exc is created (this is normally an + * unnamed object like in ExcDomain (n, dim) of class + * ExcDomain) and transferred to the deal_II_exceptions::internals::issue_error_assert_1() + * function. + * + * __PRETTY__FUNCTION__ is a macro defined by some compilers and + * gives the name of the function. If another compiler is used, we + * try to set this function to something reasonable, if the compiler + * provides us with that, and "(not available)" otherwise. + * + * In __IssueError the given data is transferred into the + * exc object by calling the set_fields() function; after that, the + * general error info is printed onto std::cerr using the + * PrintError() function of exc and finally the exception specific + * data is printed using the user defined function PrintError() (which is + * normally created using the DeclException (...) macro family. If + * it can be obtained from the operating system, the output may also contain + * a stacktrace to show where the error happened. + * + * After printing all this information, + * deal_II_exceptions::internals::abort() is called (with one + * exception, see the end of this section). This terminates the + * program, which is the right thing to do for this kind of error + * checking since it is used to detect programming errors rather than + * run-time errors; a program can, by definition, not recover from + * programming errors. + * + * If the preprocessor variable DEBUG is not set, then nothing + * happens, i.e. the Assert macro is expanded to {}. + * + * Sometimes, there is no useful condition for an exception other + * than that the program flow should not have reached a certain point, + * e.g. a default section of a switch statement. In this case, + * raise the exception by the following construct: + * @verbatim + * Assert (false, ExcInternalError()); + * @endverbatim + * + * As mentioned above, the program is terminated once a call to + * Assert fails. However, there is one case where we do not want + * to do this, namely when a C++ exception is active. The usual case + * where this happens is that someone throws an exception through the + * AssertThrow mechanism (see below) which, while the stack is + * unwound, leads to the destruction of other objects in stack frames + * above. If other objects refer to the objects being thus destroyed, + * some destructors raise an exception through Assert. If we + * would abort the program then, we would only ever see the message + * that an object is being destroyed which is still referenced from + * somewhere, but we would never see the original exception that + * triggered this. (You can see it in the debugger by putting a break + * point on the function __throw, but you cannot see it from the + * program itself.) In that case, we use a C++ standard library + * function to detect the presence of another active exception and do + * not terminate the program to allow that the thrown exception + * propagates to some place where its message can be displayed. + * + * Since it is common that one failed assertion leads to a whole + * chain of others, we only ever print the very first message. If the + * program is then aborted, that is no problem. If it is not (since a + * C++ exception is active), only the first is displayed and a + * message about suppressed follow-up messages is shown. + * + * + *

Use of run-time exceptions

+ * + * For this mode, the standard C++ throw and catch concept exists. We + * want to keep to this, but want to extend it a bit. In general, the + * structure is the same, i.e. you normally raise and exception by + * @code + * if (!(cond)) + * throw ExcSomething(); + * @endcode + * and catch it using the statement + * @code + * try { + * do_something (); + * } + * catch (exception &e) { + * std::cerr << "Exception occured:" << std::endl + * << e.what () + * << std::endl; + * do_something_to_reciver (); + * }; + * @endcode + * exception is a standard C++ class providing basic functionality for + * exceptions, such as the virtual function what() which returns some + * information on the exception itself. This information is useful if an + * exception can't be handled properly, in which case as precise a description + * as possible should be printed. + * + * The problem here is that to get significant and useful information out + * of what(), it is necessary to overload this function in out exception + * class and call the throw operator with additional arguments to the + * exception class. The first thing, overloading the what function is + * done using the DeclExceptionN macros, but putting the right information, + * which is the same as explained above for the Assert expansion, requires + * some work if one would want to write it down each time: + * @code + * if (!(cond)) + * { + * ExcSomething e(additional information); + * e.set_fields (__FILE__, __LINE__, __PRETTY_FUNCTION__, + * "condition as a string", + * "name of condition as a string"); + * throw e; + * }; + * @endcode + * + * For this purpose, the macro AssertThrow was invented. It does + * mainly the same job as does the Assert macro, but it does not + * kill the program, it rather throws an exception as shown above. The mode + * of usage is + * @code + * AssertThrow (cond, ExcSomething(additional information)); + * @endcode + * + * The condition to be checked is incorporated into the macro in order to + * allow passing the violated condition as a string. The expansion of the + * AssertThrow macro is not affected by the DEBUG + * preprocessor variable. + * + * + *

Description of the DeclExceptionN macro family

+ * + * Declare an exception class without any additional parameters. + * There is a whole family of DeclException? macros + * where ? is to be replaced by the number of additional + * parameters (0 to 5 presently). + * + * The syntax is as follows: + * @code + * DeclException2 (ExcDomain, + * int, + * int, + * << " i=" << arg1 << ", m=" << arg2); + * @endcode + * The first is the name of the exception class to be created. + * The next arguments are the types of the parameters (in this + * case there are two type names needed) and finally the output + * sequence with which you can print additional information. + * + * The syntax of the output sequence is a bit weird but gets + * clear once you see how this macro is defined: + * @code + * class name : public ExceptionBase { + * public: + * name (const type1 a1, const type2 a2) : + * arg1 (a1), arg2(a2) {}; + * virtual void print_info (std::ostream &out) const { + * out outsequence << std::endl; + * }; + * private: + * type1 arg1; + * type2 arg2; + * }; + * @endcode * + * If declared as specified, you can later use this exception class + * in the following manner: + * @code + * int i=5; + * int m=3; + * Assert (i of file . + * The violated condition was: + * iDeclException0(name) macro, no types and + * also no output sequence is allowed. + * * @author Wolfgang Bangerth, 1998-2006 */ -- 2.39.5