Classes | Public Member Functions | Private Attributes | Related Functions | List of all members
PLMD::Exception Class Reference

#include <Exception.h>

Inheritance diagram for PLMD::Exception:
Inheritance graph
[legend]

Classes

class  Assertion
 Auxiliary containing the failed assertion. More...
 
class  Location
 Auxiliary containing the location of the exception in the file. More...
 
class  Throw
 Auxiliary class used to throw exceptions. More...
 

Public Member Functions

 Exception ()
 Default constructor with no message. More...
 
 Exception (const Exception &e)
 Copy constructor. More...
 
 Exception (const std::string &msg)
 Constructor compatible with PLUMED <=2.4. More...
 
 ~Exception () noexcept override
 Destructor should be defined and should not throw other exceptions. More...
 
Exceptionoperator<< (const Assertion &)
 Insert assertion. More...
 
Exceptionoperator<< (const Location &)
 Insert location. More...
 
Exceptionoperator<< (const std::string &)
 Insert string. More...
 
template<typename T >
Exceptionoperator<< (const T &x)
 Insert anything else. More...
 
Exceptionoperator= (const Exception &e)
 Assignment. More...
 
const char * stack () const
 Returns the stack trace as a string. More...
 
const std::array< void *, 128 > & trace () const noexcept
 Returns the callstack. More...
 
int trace_n () const noexcept
 Returns the number of elements in the trace array. More...
 
const char * what () const noexcept override
 Returns the error message. More...
 

Private Attributes

std::array< void *, 128 > callstack
 Stack trace, computed at construction. More...
 
int callstack_n =0
 Number of frames in stack, computed at construction. More...
 
std::string msg
 Reported message. Can be updated. More...
 
bool note =true
 Flag to remember if we have to write the +++ message follows +++ string. More...
 
std::string stackTrace
 Parsed stack trace. Built at first use, thus mutable. More...
 
std::stringstream stream
 Stream used to insert objects. More...
 

Related Functions

(Note that these are not member functions.)

#define plumed_assert(test)   if(!(test)) plumed_error() << PLMD::Exception::Assertion(#test)
 
#define plumed_dbg_assert(test)   if(!(test)) PLMD::Exception::Throw() <<= PLMD::ExceptionDebug() << plumed_here << PLMD::Exception::Assertion(#test) << "(this check is enabled only in debug builds)\n"
 
#define plumed_dbg_massert(test, msg)   plumed_dbg_assert(test) << msg
 
#define plumed_error()   throw PLMD::ExceptionError() << plumed_here
 
#define plumed_error_nested()   PLMD::Exception::Throw() <<= PLMD::ExceptionError() << plumed_here
 
#define plumed_here   PLMD::Exception::Location(PLUMED_MODULE_DIR __FILE__,__LINE__,__PLUMED_FUNCNAME)
 
#define plumed_massert(test, msg)   plumed_assert(test) << msg
 
#define plumed_merror(msg)   plumed_error() << msg
 

Detailed Description

Class to deal with Plumed runtime errors.

This class and the related macros can be used to detect programming errors. Typical cases are internal inconsistencies or errors in the plumed<->MD interface. Mistakes made by final users (i.e. in the plumed.dat file) should probably be documented in some better way (e.g. printing parts of the manual in the output). However, also this class allows for significant information to be attached. Let's try to make error messages as informative as possible!

Note
This class has been rewritten in PLUMED 2.5. It works in a backward compatible manner, but is much more flexible. The main novelty is that we can use insertion operators to add arbitrary messages, as in plumed_error()<<"check this vector "<<v; See below for more details.

To throw an error, just throw a c++ exception

  if(something_bad) throw Exception();

or better add an error message to that

  if(something_bad) throw Exception("describe the error here");

As of PLUMED 2.5 you can add multiple messages, they will just be concatenated, but to do se you should use the insertion operator. Notice that anything that can be formatted with an insertion operator can go to the exception, even a Vector

  Vector v;
  if(something_bad) throw Exception()<<"problem with this "<<v;

In principle you can mix the two syntax (add a message as an argument and insert others with <<), however it is not very clear and should be avoided. We only allow using arguments in parenthesis in order to keep backward compatibility.

Using macros

In order to provide more context, especially for debugging, it might be useful to know where the exception originated from. The macros below add information about the exact location of the error in the file (filename, line and, when available, function name). Macros ending in "error" unconditionally throw the exception, whereas macros ending in "assert" first perform a conditional check (similarly to standard assert()). An extra m in the name (e.g. plumed_merror) indicates a macro that provides a message as its argument. However, as of PLUMED 2.5 we should prefer adding messages using insertion operators.

// this is correct but not recommended. add a message please!
  plumed_assert(a>0);

// this is the old syntax (with argument).
// this syntax is basically available for backward compatibility.
  plumed_massert(a>0,"a should be larger than zero);

// this is the recommended syntax, with insertion operators.
// it allows to easily insert multiple objects
  plumed_assert(a>0)<<"a should be larger than zero. a="<<a;

// same as above, but the test is made explicitly:
  if(a<=0) plumed_error();
  if(a<=0) plumed_error("a should be larger than zero);
  if(a<=0) plumed_error()<<"a should be larger than zero. a="<<a;

The additional macros plumed_dbg_assert() and plumed_dbg_massert() are similar to plumed_assert() and plumed_massert() respectively, but the corresponding check is only performed when NDEBUG macro is not defined. They should be used when the check is expensive and should be skipped in production code. So, for instance, in the following case:

  plumed_dbg_assert(expensive_function(i)>0)<<"message";

expensive_function() is not called in the production code. Notice that the compiler should be able to completely optimize away the whole statement including functions used to produce the message as in this example:

  plumed_dbg_assert(expensive_function(i)>0)<<"I did this check "<<other_expensive_function(i);

Finally, notice that there is another macro available, plumed_here. In can be used in order to create an exception with information about the line/file coordinates without trowing it. That is, the two following syntaxes are equivalent

// First way, all at once
plumed_error()<<"some message";
/////////////////////////////////
// Second way, one step at a time
// Create exception
Exception e;
// Append information about line and file
e<<plumed_here;
// Append some other message
e<<"some message";
// Throw the resulting exception
throw e;

Exceptions can be caught within plumed or outside of it. E.g., in an external c++ code using PLUMED as a library, one can type

  try{
    plumed.cmd("setPrecision",n);
  } catch (const std::exception & e) {
    std::printf("ee %s",e.what());
    exit(1);
  }

This can be useful if an external code wants to exit in a controlled manner (e.g. flushing files, printing the error message in a specific file, etc.) but is anyway limited to c++ codes. Moreover, since these errors are expected to be unrecoverable, the MD code will usually not be able to do something more clever than exiting.

Note
We store message and stack trace in growing strings. This is in principle not recommended, since copying the exception might fail if copying the string throw another exception. However, this has been like this in all previous PLUMED versions. In case it is necessary, we can replace it later with a fixed size array placed on the stack.

Constructor & Destructor Documentation

◆ Exception() [1/3]

PLMD::Exception::Exception ( )

Default constructor with no message.

Only records the stack trace.

◆ Exception() [2/3]

PLMD::Exception::Exception ( const std::string &  msg)
inlineexplicit

Constructor compatible with PLUMED <=2.4.

◆ Exception() [3/3]

PLMD::Exception::Exception ( const Exception e)
inline

Copy constructor.

Needed to make sure stream is not copied

◆ ~Exception()

PLMD::Exception::~Exception ( )
inlineoverridenoexcept

Destructor should be defined and should not throw other exceptions.

Member Function Documentation

◆ operator<<() [1/4]

Exception& PLMD::Exception::operator<< ( const Assertion )

Insert assertion.

Format the assertion properly

◆ operator<<() [2/4]

Exception& PLMD::Exception::operator<< ( const Location )

Insert location.

Format the location properly.

◆ operator<<() [3/4]

Exception& PLMD::Exception::operator<< ( const std::string &  )

Insert string.

Append this string to the message.

◆ operator<<() [4/4]

template<typename T >
Exception& PLMD::Exception::operator<< ( const T &  x)
inline

Insert anything else.

This allows to dump also other types (e.g. double, or even Vector). Anything that can be written on a stream can go here.

◆ operator=()

Exception& PLMD::Exception::operator= ( const Exception e)
inline

Assignment.

Needed to make sure stream is not copied

◆ stack()

const char * PLMD::Exception::stack ( ) const

Returns the stack trace as a string.

This function is slow as it requires building a parsed string. If storing the stack for later usage, you might prefer to use trace().

◆ trace()

const std::array<void*,128>& PLMD::Exception::trace ( ) const
inlinenoexcept

Returns the callstack.

◆ trace_n()

int PLMD::Exception::trace_n ( ) const
inlinenoexcept

Returns the number of elements in the trace array.

◆ what()

const char* PLMD::Exception::what ( ) const
inlineoverridenoexcept

Returns the error message.

In case the environment variable PLUMED_STACK_TRACE was defined and equal to yes when the exception was raised, the error message will contain the stack trace as well.

Friends And Related Function Documentation

◆ plumed_assert

#define plumed_assert (   test)    if(!(test)) plumed_error() << PLMD::Exception::Assertion(#test)
related

Launches plumed_merror only if test evaluates to false. The string describing the test is also reported. Further messages can be inserted with <<.

◆ plumed_dbg_assert

#define plumed_dbg_assert (   test)    if(!(test)) PLMD::Exception::Throw() <<= PLMD::ExceptionDebug() << plumed_here << PLMD::Exception::Assertion(#test) << "(this check is enabled only in debug builds)\n"
related

Same as plumed_assert, but only evaluates the condition if NDEBUG is not defined.

◆ plumed_dbg_massert

#define plumed_dbg_massert (   test,
  msg 
)    plumed_dbg_assert(test) << msg
related

Same as plumed_massert, but only evaluates the condition if NDEBUG is not defined.

◆ plumed_error

#define plumed_error ( )    throw PLMD::ExceptionError() << plumed_here
related

Throw an exception with information about the position in the file. Messages can be inserted with plumed_error()<<"message".

◆ plumed_error_nested

#define plumed_error_nested ( )    PLMD::Exception::Throw() <<= PLMD::ExceptionError() << plumed_here
related

Throw a nested exception with information about the position in the file. It preliminary checks if we are in a catch block. If so, the caught exception is rethrown as nested. If not, it throws a normal ExceptionError. NB in theory we could have just redefined plumed_error to this, but for some reason cppcheck does not understand that the <<= operator used here is [[noreturn]] and thus gives many false warnings

◆ plumed_here

#define plumed_here   PLMD::Exception::Location(PLUMED_MODULE_DIR __FILE__,__LINE__,__PLUMED_FUNCNAME)
related

Auxiliary macro that generates a PLMD::Exception::Location object. Might be useful if we want to use derived exceptions that could be thrown using throw DerivedException()<<plumed_here<<" "<<other stuff". It is used in the macros below to throw PLMD::Exception.

◆ plumed_massert

#define plumed_massert (   test,
  msg 
)    plumed_assert(test) << msg
related

Launches plumed_merror only if test evaluates to false. The string describing the test is also reported, in addition to messages reported in the extra argument. Mostly available for backward compatibility.

◆ plumed_merror

#define plumed_merror (   msg)    plumed_error() << msg
related

Throw an exception with information about the position in the file and a message. Mostly available for backward compatibility

Member Data Documentation

◆ callstack

std::array<void*,128> PLMD::Exception::callstack
private

Stack trace, computed at construction.

◆ callstack_n

int PLMD::Exception::callstack_n =0
private

Number of frames in stack, computed at construction.

◆ msg

std::string PLMD::Exception::msg
private

Reported message. Can be updated.

◆ note

bool PLMD::Exception::note =true
private

Flag to remember if we have to write the +++ message follows +++ string.

Needed so that the string appears only at the beginning of the message.

◆ stackTrace

std::string PLMD::Exception::stackTrace
mutableprivate

Parsed stack trace. Built at first use, thus mutable.

◆ stream

std::stringstream PLMD::Exception::stream
private

Stream used to insert objects.

It is not copied when the Exception is copied.


The documentation for this class was generated from the following files: