Exceptions
    

Options

Exceptions are raised if an error is detected. Seldon is able to check for several mistakes:

  • SELDON_CHECK_IO: checks input/output operations on disk.

  • SELDON_CHECK_MEMORY: checks memory allocations and deallocations.

  • SELDON_CHECK_DIMENSIONS: checks that the dimensions of involved structures are compatible. Notice that there are methods in which the compatibility is not checked however.

  • SELDON_CHECK_BOUNDS: checks that indices are not out of range.

To enable SELDON_CHECK_MEMORY, for example, put (before #include <Seldon.hxx>):

#define SELDON_CHECK_MEMORY

Alternatively, there are debug levels:

  • SELDON_DEBUG_LEVEL_0: nothing is checked.

  • SELDON_DEBUG_LEVEL_1: equivalent to SELDON_CHECK_IO plus SELDON_CHECK_MEMORY.

  • SELDON_DEBUG_LEVEL_2: equivalent to SELDON_DEBUG_LEVEL_1 plus SELDON_CHECK_DIMENSIONS.

  • SELDON_DEBUG_LEVEL_3: equivalent to SELDON_DEBUG_LEVEL_2 plus SELDON_CHECK_BOUNDS.

  • SELDON_DEBUG_LEVEL_4: equivalent to SELDON_DEBUG_LEVEL_3.

In practice, it is advocated to choose SELDON_DEBUG_LEVEL_4 in the development stage and SELDON_DEBUG_LEVEL_2 for the stable version. Indeed SELDON_DEBUG_LEVEL_4 slows down the program but checks many things and SELDON_DEBUG_LEVEL_2 should not slow down the program and ensures that it is reasonably safe.

Development stage:

#define SELDON_DEBUG_LEVEL_4

Stable version:

#define SELDON_DEBUG_LEVEL_2

Exceptions raised

The objects that may be launched by Seldon are of type: WrongArgument, NoMemory, WrongDim, WrongIndex, WrongRow, WrongCol, IOError and LapackError. They all derive from Error. They provide the method What that returns a string explaining the error, and the method CoutWhat that displays on screen this explanation. Therefore, to catch an exception raised by Seldon, put:

catch(Seldon::Error& Err)
{
Err.CoutWhat();
}

Two macros are defined to help:

TRY:

#define TRY try {

END:

#define END                                                     \
  }                                                             \
    catch(Seldon::Error& Err)                                   \
      {                                                         \
        Err.CoutWhat();                                         \
        return 1;                                               \
      }                                                         \
    catch (std::exception& Err)                                 \
      {                                                         \
        cout << "C++ exception: " << Err.what() << endl;        \
        return 1;                                               \
      }                                                         \
    catch (std::string& str)                                    \
      {                                                         \
        cout << str << endl;                                    \
        return 1;                                               \
      }                                                         \
    catch (const char* str)                                     \
      {                                                         \
        cout << str << endl;                                    \
        return 1;                                               \
      }                                                         \
    catch(...)                                                  \
      {                                                         \
        cout << "Unknown exception..." << endl;                 \
        return 1;                                               \
      }

It is advocated that you enclose your code (in the main function) with TRY; and END;:

int main(int argc, char** argv)
{
  TRY;

  // Here goes your code.

  END;

  return 0;
}

Exceptions and debugging

Suppose your code contains an error and raises an exception. You probably want to identify the function that raised the exception. The error message should contain the name of the function. But you probably want to know the exact line where the error occurred and the sequence of calls. Then, you have two options, using a debugger.

One option is to place a breakpoint in Error::Error(string function = "", string comment = "") (see file share/Errors.cxx) because this constructor should be called before the exception is actually raised.

Another option, more convenient because no breakpoint is to be placed, is to define SELDON_WITH_ABORT. With that flag activated, if a Seldon exception is raised, the program will simply abort. If you include SeldonLib.hxx, this flag is actually already activated. The call stack is then at hand. See the example below, using gdb under Linux. The program error.cpp demonstrates the technique:

#define SELDON_WITH_ABORT // not needed with SeldonLib.hxx
#define SELDON_DEBUG_LEVEL_4 // which checks bounds.
#include "Seldon.hxx"
using namespace Seldon;

int main(int argc, char** argv)
{
  TRY;

  IVect V(3);
  cout << "Bad access: " << V(3) << endl;

  END;

  return 0;
}

The error and the calls sequence are easy to obtain:

$ g++ -o error -g -I ~/src/seldon error.cpp
$ ./error                                        
ERROR!                                                     
Index out of range in Vector<VectFull>::operator().        
   Index should be in [0, 2], but is equal to 3.           
Aborted
$ gdb ./error
GNU gdb 6.8-debian
Copyright (C) 2008 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu"...
(gdb) run
Starting program: /tmp/error 
ERROR!
Index out of range in Vector<VectFull>::operator().
   Index should be in [0, 2], but is equal to 3.

Program received signal SIGABRT, Aborted.
0x00007f4b7e136fb5 in raise () from /lib/libc.so.6
(gdb) up
#1  0x00007f4b7e138bc3 in abort () from /lib/libc.so.6
(gdb) up
#2  0x000000000040308e in WrongIndex (this=0x1a83370, function=
        {static npos = 18446744073709551615, _M_dataplus = {<std::allocator<char>> = {<__gnu_cxx::new_allocator<char>> = {<No data fields>},
                                                              <No data fields>}, _M_p = 0x7fff86e3e0f0 "H?\001"}}, comment=
        {static npos = 18446744073709551615, _M_dataplus = {<std::allocator<char>> = {<__gnu_cxx::new_allocator<char>> = {<No data fields>},
                           <No data fields>}, _M_p = 0x7fff86e3e100 "??\001"}}) at /home/mallet/src/seldon/share/Errors.cxx:206
206         abort();
(gdb) up
#3  0x0000000000404888 in Seldon::Vector<int, Seldon::VectFull, Seldon::MallocAlloc<int> >::operator() (this=0x7fff86e3e1c0, i=3)
    at /home/mallet/src/seldon/vector/Vector.cxx:440
440           throw WrongIndex("Vector<VectFull>::operator()",
(gdb) up
#4  0x000000000040364b in main (argc=1, argv=0x7fff86e3e2d8) at error.cpp:11
11        cout << "Bad access: " << V(3) << endl;

Notes

Apart from exceptions, two useful macros are defined to ease the debugging activities:

ERR:

#define ERR(x) cout << "Hermes - " #x << endl

DISP:

#define DISP(x) cout << #x ": " << x << endl

In a code:

ERR(5);
ERR(5a);
int i = 7;
DISP(i + 1);
ERR(Last line);

returns on screen:

Hermes - 5
Hermes - 5a
i + 1: 8
Hermes - Last line


Classes

Error Base class for exceptions in Seldon
Undefined Error for undefined functions
WrongArgument Error for wrong arguments
NoMemory Error for insufficient memory
WrongDim Error for wrong dimensions
WrongIndex Error for wrong indexes
WrongRow Error for a wrong row
WrongCol Error for a wrong col
IOError Error for input/output
SolverMaximumIterationError Error for maximal iterations reached for a solver
SolverDivergenceError Error because of a divergent algorithm
LapackError Error when calling a Lapack function


Functions

CheckBounds Checks if the indexes of an array/matrix are out of bounds
CheckBoundsSym Checks if the indexes of a symmetric matrix are out of bounds
CheckBoundsTriang Checks if the indexes of a triangular matrix are out of bounds


Error

Syntax :

  Error();
  Error(string function);
  Error(string function, string comment);
  Error(string description, string function, string comment);

Example :

// if you want to raise an exception
thow Error();

// you can provide optional parameters
// such as the function name and a comment
throw Error("MyFunctionName", "Failed to complete the algorithm");

// or the description of the error
throw Error("NoConvergence", "MyFunctionName", "Failed to complete the algorithm");

// if you catch an error
try
{
// your code
}
catch (Error& Err)
{
  // you can display the error with CoutWhat
  Err.CoutWhat();
  // or retrieve the message in a string
  string res = Err.What();
}

Location :

Errors.cxx

Undefined

Syntax :

  Undefined();
  Undefined(string function);
  Undefined(string function, string comment);

Example :

// if you want to raise an exception because of an undefined function
thow Undefined();

// you can provide optional parameters
// such as the function name and a comment
throw Undefined("MyFunctionName", "Function not defined for these arguments");

// if you catch an error
try
{
// your code
}
catch (Undefined& Err)
{
  // you can display the error with CoutWhat
  Err.CoutWhat();
  // or retrieve the message in a string
  string res = Err.What();
}

Location :

Errors.cxx

WrongArgument

Syntax :

  WrongArgument();
  WrongArgument(string function);
  WrongArgument(string function, string comment);

Example :

// if you want to raise an exception because of a wrong argument
thow WrongArgument();

// you can provide optional parameters
// such as the function name and a comment
throw WrongArgument("MyFunctionName", "Argument 2 must be positive");

// if you catch an error
try
{
// your code
}
catch (WrongArgument& Err)
{
  // you can display the error with CoutWhat
  Err.CoutWhat();
  // or retrieve the message in a string
  string res = Err.What();
}

Location :

Errors.cxx

NoMemory

Syntax :

  NoMemory();
  NoMemory(string function);
  NoMemory(string function, string comment);

Example :

// if you want to raise an exception because of insufficient memory
thow NoMemory();

// you can provide optional parameters
// such as the function name and a comment
throw NoMemory("MyFunctionName", "Not enough memory to complete the factorization");

// if you catch an error
try
{
// your code
}
catch (NoMemory& Err)
{
  // you can display the error with CoutWhat
  Err.CoutWhat();
  // or retrieve the message in a string
  string res = Err.What();
}

Location :

Errors.cxx

Undefined

Syntax :

  WrongDim();
  WrongDim(string function);
  WrongDim(string function, string comment);

Example :

// if you want to raise an exception because of an incorrect dimension
thow WrongDim();

// you can provide optional parameters
// such as the function name and a comment
throw WrongDim("MyFunctionName", "Number of rows is too small");

// if you catch an error
try
{
// your code
}
catch (WrongDim& Err)
{
  // you can display the error with CoutWhat
  Err.CoutWhat();
  // or retrieve the message in a string
  string res = Err.What();
}

Location :

Errors.cxx

Undefined

Syntax :

  WrongIndex();
  WrongIndex(string function);
  WrongIndex(string function, string comment);

Example :

// if you want to raise an exception because of an index out of bounds
thow WrongIndex();

// you can provide optional parameters
// such as the function name and a comment
throw WrongIndex("MyFunctionName", "Index i is not in [0, 3]");

// if you catch an error
try
{
// your code
}
catch (WrongIndex& Err)
{
  // you can display the error with CoutWhat
  Err.CoutWhat();
  // or retrieve the message in a string
  string res = Err.What();
}

Location :

Errors.cxx

Undefined

Syntax :

  WrongRow();
  WrongRow(string function);
  WrongRow(string function, string comment);

Example :

// if you want to raise an exception because of an incorrect row
thow WrongRow();

// you can provide optional parameters
// such as the function name and a comment
throw WrongRow("MyFunctionName", "row is null");

// if you catch an error
try
{
// your code
}
catch (WrongRow& Err)
{
  // you can display the error with CoutWhat
  Err.CoutWhat();
  // or retrieve the message in a string
  string res = Err.What();
}

Location :

Errors.cxx

WrongCol

Syntax :

  WrongCol();
  WrongCol(string function);
  WrongCol(string function, string comment);

Example :

// if you want to raise an exception because of an undefined function
thow WrongCol();

// you can provide optional parameters
// such as the function name and a comment
throw WrongCol("MyFunctionName", "column contains NaN");

// if you catch an error
try
{
// your code
}
catch (WrongCol& Err)
{
  // you can display the error with CoutWhat
  Err.CoutWhat();
  // or retrieve the message in a string
  string res = Err.What();
}

Location :

Errors.cxx

IOError

Syntax :

  IOError();
  IOError(string function);
  IOError(string function, string comment);

Example :

// if you want to raise an exception because of an input/output error
thow IOError();

// you can provide optional parameters
// such as the function name and a comment
throw IOError("MyFunctionName", "File does not exist");

// if you catch an error
try
{
// your code
}
catch (IOError& Err)
{
  // you can display the error with CoutWhat
  Err.CoutWhat();
  // or retrieve the message in a string
  string res = Err.What();
}

Location :

Errors.cxx

Undefined

Syntax :

  SolverMaximumIterationError();
  SolverMaximumIterationError(string function);
  SolverMaximumIterationError(string function, string comment);

Example :

// if you want to raise an exception because of an undefined function
thow SolverMaximumIterationError();

// you can provide optional parameters
// such as the function name and a comment
throw SolverMaximumIterationError("MyFunctionName", "Maximum number of iterations reached");

// if you catch an error
try
{
// your code
}
catch (SolverMaximumIterationError& Err)
{
  // you can display the error with CoutWhat
  Err.CoutWhat();
  // or retrieve the message in a string
  string res = Err.What();
}

Location :

Errors.cxx

Undefined

Syntax :

  SolverDivergenceError();
  SolverDivergenceError(string function);
  SolverDivergenceError(string function, string comment);

Example :

// if you want to raise an exception because of an undefined function
thow SolverDivergenceError();

// you can provide optional parameters
// such as the function name and a comment
throw SolverDivergenceError("MyFunctionName", "Algorithm diverged");

// if you catch an error
try
{
// your code
}
catch (SolverDivergenceError& Err)
{
  // you can display the error with CoutWhat
  Err.CoutWhat();
  // or retrieve the message in a string
  string res = Err.What();
}

Location :

Errors.cxx

IOError

Syntax :

  LapackError();
  LapackError(string function);
  LapackError(string function, string comment);

Example :

// if you want to raise an exception because of a Lapack error
thow LapackError();

// you can provide optional parameters
// such as the function name and a comment
throw LapackError("MyFunctionName", "Error while calling Lapack");

// if you catch an error
try
{
// your code
}
catch (LapackError& Err)
{
  // you can display the error with CoutWhat
  Err.CoutWhat();
  // or retrieve the message in a string
  string res = Err.What();
}

Location :

Errors.cxx

CheckBounds

Syntax :

void CheckBounds(int i, int length, string name);
void CheckBounds(int i, int j, int length1, int length2, string name);
void CheckBounds(int i, int j, int k, int length1, int length2, int length3, string name);
etc

These functions check if the index i is contained in the interval [0, length-1]. If it is not the case, it will raise an exception (WrongIndex). For a matrix, it will check that the first index i is contained in the interval [0, length1-1] and the second index j in the interval [0, length2-1]. Similarly, you can give more indexes (up to 9 indexes). The last argument is the function name.

Example :

// you want to check if i is contained in [0, 2] :
CheckBounds(i, 3, "MyFunction");

Location :

Errors.cxx

CheckBoundsSym

Syntax :

void CheckBoundsSym(int i, int j, int m, int n, string name);

This function checks if the index i is contained in the interval [0, m-1], and if j is contained in the interval [0, n-1]. Moreover, it checks that j is greater or equal to i such that you can modify only upper part of matrix.

Example :

// you want to check if (i, j) is contained in upper part of a matrix 3x4 :
CheckBoundsSym(i, j, 3, 4, "MyFunction");

Location :

Errors.cxx

CheckBoundsTriang

Syntax :

void CheckBoundsTriang(int i, int j, int m, int n, bool upper, string name);

This function checks if the index i is contained in the interval [0, m-1], and if j is contained in the interval [0, n-1]. Moreover, if the argument upper is true, it checks that j is greater or equal to i s uch that you can modify only upper part of the matrix. If the argument upper is false, it checks that you are in the lower part of the matrix.

Example :

// you want to check if (i, j) is contained in the lower part of a matrix 3x4 :
CheckBoundsTriang(i, j, 3, 4, false, "MyFunction");

Location :

Errors.cxx