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.
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.
-
inline const std::string &GetMessage() const
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.
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.
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.
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
.