2.9. Error Handling

VTK‑m contains several mechanisms for checking and reporting error conditions.

2.9.1. Runtime Error Exceptions

VTK‑m uses exceptions to report errors. All exceptions thrown by VTK‑m will be a subclass of vtkm::cont::Error. For simple error reporting, it is possible to simply catch a vtkm::cont::Error and report the error message string reported by the vtkm::cont::Error::GetMessage() method.

Example 2.57 Simple error reporting.
 1int main(int argc, char** argv)
 2{
 3  try
 4  {
 5    // Do something cool with VTK-m
 6    // ...
 7  }
 8  catch (const vtkm::cont::Error& error)
 9  {
10    std::cout << error.GetMessage() << std::endl;
11    return 1;
12  }
13  return 0;
14}
class Error : public std::exception

The superclass of all exceptions thrown by any VTKm function or method.

Subclassed by vtkm::cont::ErrorBadAllocation, vtkm::cont::ErrorBadDevice, vtkm::cont::ErrorBadType, vtkm::cont::ErrorBadValue, vtkm::cont::ErrorExecution, vtkm::cont::ErrorFilterExecution, vtkm::cont::ErrorInternal, vtkm::cont::ErrorUserAbort, vtkm::cont::cuda::ErrorCuda, vtkm::io::ErrorIO

Public Functions

inline const std::string &GetMessage() const

Returns a message describing what caused the error.

inline const std::string &GetStackTrace() const

Provides a stack trace to the location where this error was thrown.

inline const char *what() const noexcept override

Returns the message for the error and the stack trace for it.

This method is provided for std::exception compatibility.

inline bool GetIsDeviceIndependent() const

Returns true if this exception is device independent.

For exceptions that are not device independent, vtkm::TryExecute, for example, may try executing the code on other available devices.

There are several subclasses to vtkm::cont::Error. The specific subclass gives an indication of the type of error that occurred when the exception was thrown. Catching one of these subclasses may help a program better recover from errors.

class ErrorBadAllocation : public vtkm::cont::Error

This class is thrown when VTK-m attempts to manipulate memory that it should not.

class ErrorBadDevice : public vtkm::cont::Error

This class is thrown when VTK-m performs an operation that is not supported on the current device.

class ErrorBadType : public vtkm::cont::Error

This class is thrown when VTK-m encounters data of a type that is incompatible with the current operation.

class ErrorBadValue : public vtkm::cont::Error

This class is thrown when a VTKm function or method encounters an invalid value that inhibits progress.

class ErrorExecution : public vtkm::cont::Error

This class is thrown in the control environment whenever an error occurs in the execution environment.

class ErrorFilterExecution : public vtkm::cont::Error

This class is primarily intended to filters to throw in the control environment to indicate an execution failure due to misconfiguration e.g.

incorrect parameters, etc. This is a device independent exception i.e. when thrown, unlike most other exceptions, VTK-m will not try to re-execute the filter on another available device.

class ErrorInternal : public vtkm::cont::Error

This class is thrown when VTKm detects an internal state that should never be reached.

This error usually indicates a bug in vtkm or, at best, VTKm failed to detect an invalid input it should have.

class ErrorUserAbort : public vtkm::cont::Error

This class is thrown when vtk-m detects a request for aborting execution in the current thread.

class ErrorIO : public vtkm::cont::Error

This class is thrown when VTK-m encounters an error with the file system.

This can happen if there is a problem with reading or writing a file such as a bad filename.

2.9.2. Asserting Conditions

In addition to the aforementioned error signaling, the vtkm/Assert.h header file defines a macro named VTKM_ASSERT. This macro behaves the same as the POSIX assert macro. It takes a single argument that is a condition that is expected to be true. If it is not true, the program is halted and a message is printed. Asserts are useful debugging tools to ensure that software is behaving and being used as expected.

VTKM_ASSERT(condition)

Asserts that condition resolves to true.

If condition is false, then a diagnostic message is outputted and execution is terminated. The behavior is essentially the same as the POSIX assert macro, but is wrapped for added portability.

Like the POSIX assert macro, the check will be removed when compiling in non-debug mode (specifically when NDEBUG is defined), so be prepared for the possibility that the condition is never evaluated.

The VTKM_NO_ASSERT cmake and preprocessor option allows debugging builds to remove assertions for performance reasons.

Example 2.58 Using VTKM_ASSERT.
1template<typename T>
2VTKM_CONT T GetArrayValue(vtkm::cont::ArrayHandle<T> arrayHandle, vtkm::Id index)
3{
4  VTKM_ASSERT(index >= 0);
5  VTKM_ASSERT(index < arrayHandle.GetNumberOfValues());

Did You Know?

Like the POSIX assert, if the NDEBUG macro is defined, then VTKM_ASSERT will become an empty expression. Typically NDEBUG is defined with a compiler flag (like -DNDEBUG) for release builds to better optimize the code. CMake will automatically add this flag for release builds.

Common Errors

A helpful warning provided by many compilers alerts you of unused variables. (This warning is commonly enabled on VTK‑m regression test nightly builds.) If a function argument is used only in a VTKM_ASSERT, then it will be required for debug builds and be unused in release builds. To get around this problem, add a statement to the function of the form (void)variableName;. This statement will have no effect on the code generated but will suppress the warning for release builds.

2.9.3. Compile Time Checks

Because VTK‑m makes heavy use of C++ templates, it is possible that these templates could be used with inappropriate types in the arguments. Using an unexpected type in a template can lead to very confusing errors, so it is better to catch such problems as early as possible. The VTKM_STATIC_ASSERT macro, defined in vtkm/StaticAssert.h makes this possible. This macro takes a constant expression that can be evaluated at compile time and verifies that the result is true.

In the following example, VTKM_STATIC_ASSERT and its sister macro VTKM_STATIC_ASSERT_MSG, which allows you to give a descriptive message for the failure, are used to implement checks on a templated function that is designed to work on any scalar type that is represented by 32 or more bits.

Example 2.59 Using VTKM_STATIC_ASSERT.
1template<typename T>
2VTKM_EXEC_CONT void MyMathFunction(T& value)
3{
4  VTKM_STATIC_ASSERT((std::is_same<typename vtkm::TypeTraits<T>::DimensionalityTag,
5                                   vtkm::TypeTraitsScalarTag>::value));
6
7  VTKM_STATIC_ASSERT_MSG(sizeof(T) >= 4,
8                         "MyMathFunction needs types with at least 32 bits.");

Did You Know?

In addition to the several trait template classes provided by VTK‑m to introspect C++ types, the C++ standard type_traits header file contains several helpful templates for general queries on types. Example 2.59 demonstrates the use of one such template: std::is_same.

Common Errors

Many templates used to introspect types resolve to the tags std::true_type and std::false_type rather than the constant values true and false that VTKM_STATIC_ASSERT expects. The std::true_type and std::false_type tags can be converted to the Boolean literal by adding ::value to the end of them. Failing to do so will cause VTKM_STATIC_ASSERT to behave incorrectly. Example 2.59 demonstrates getting the Boolean literal from the result of std::is_same.