Error Handling

内容表

关于

The MAXON API uses a custom error reporting system. In case of an error, a function can return an error object. The return value and the error object are stored in a maxon::Result object. Within a function scope it is also necessary to handle errors returned by sub-functions.

Return Errors

A function that returns a maxon::Result object can either return just the plain return value or a complex error object. This error object can contain detailed information on the error that occurred. For more details on the maxon::Result class see Error Result . For a list of default error types see Error Types .

// This example shows a function that returns a number or an error.

//---------------------------------------------------------------------------------------- // Creates a random number by rolling a dice. // @return Random number or UnknownError if the dice could not be rolled. //---------------------------------------------------------------------------------------- static maxon::Result<maxon::Int> GetRandomNumber() { maxon::Int number = 0;

if (RollDice(number) == false ) return maxon::UnknownError( MAXON_SOURCE_LOCATION , "Could not roll the dice." _s);
return number; }

Functions that do not return any value can return Result<void> :

// This example shows a function that does not return a value // but can return an error in case of an invalid argument or just maxon::OK. // Note: Real code should use a reference and not a pointer.

//---------------------------------------------------------------------------------------- // Increments the given maxon::Int value. // Returns an NullptrError if an invalid argument is given. // @param[in,out] number Pointer to an maxon::Int value. // @return OK on success. //---------------------------------------------------------------------------------------- static maxon::Result<void> IncrementValue( maxon::Int * const number) { if (number == nullptr ) return maxon::NullptrError( MAXON_SOURCE_LOCATION ); *number = *number + 1; return maxon::OK ; }

It is possible to create an error object before it is needed to increase the performance in speed critical tasks:

// This example uses a preallocated error object to return an error efficiently.

// preallocate the illegal-argument-error g_sampleArgumentError static MAXON_ERROR_PREALLOCATE (g_sampleArgumentError, []() { return maxon::IllegalArgumentError( MAXON_SOURCE_LOCATION ); }); static maxon::Result<maxon::Float32> SampleGradient( maxon::Float32 pos) { // check range // if out of bounds return the pre-allocated error if (pos < 0.0 || pos > 1.0) return g_sampleArgumentError; return Sample(pos); }

Error Scope

Within a given error scope one must define how errors returned by sub-functions are handled.

注意
An error returned by a function must be handled explicitly. Ignoring the returned error object will result in a compile error on certain systems.

Best practice to handle errors is typically to declare an error scope and to simply return the error returned by a sub-function:

In such an error scope one can simply return from the function if an error occurred in a sub-function:

//---------------------------------------------------------------------------------------- // Returns a random float value. // @return A random maxon::Float value. //---------------------------------------------------------------------------------------- static maxon::Result<maxon::Float> GetRandomFloat() { // declare error scope iferr_scope ;

// return if an error is returned const maxon::Int randomNumber = GetRandomNumber() iferr_return ; const maxon :: Float randomFloat = ( maxon :: Float )randomNumber / numberOfFaces; return randomFloat; }

If a simple error scope is declared with iferr_scope, the attribute iferr_return will return from the function returning the detected error. In contrast, iferr_scope_handler allows to define a function that is called before iferr_return will return.

注意
When called with iferr_return, the return value of iferr_scope_handler is used as the return value of the function.

Compare also Finally .

// This function handles the error returned by GetRandomNumber() // by printing the error to the console and returning a default value.

//---------------------------------------------------------------------------------------- // Returns a random float value. // @return A random maxon::Float value. //---------------------------------------------------------------------------------------- static maxon::Float GetRandomFloat() { iferr_scope_handler { // is called by iferr_return before it returns from the function DiagnosticOutput ( "GetRandomFloat() error: @" , err);

// defines the return value return 0.0; };

// return if an error is returned const maxon::Int randomNumber = GetRandomNumber() iferr_return ; const maxon :: Float randomFloat = ( maxon :: Float )randomNumber / numberOfFaces; return randomFloat; }

It is also possible to simply check if a called function returned an error or not.

// This function checks if GetRandomNumber() returns an error. // If so, this error is returned by the function itself.

//---------------------------------------------------------------------------------------- // Returns a random float value. // @return A random maxon::Float value. //---------------------------------------------------------------------------------------- static maxon::Result<maxon::Float> GetRandomFloat() { maxon::Int randomNumber = 0;

// return if an error is returned iferr (randomNumber = GetRandomNumber()) { // "err" is defined in iferr return err; } const maxon::Float randomFloat = ( maxon::Float )randomNumber / numberOfFaces; return randomFloat; }

If a new error is created within a function it is typically just returned. If one wants iferr_scope_handler to be called before one must use iferr_throw:

// This function prints all errors that occur before the function is left. // iferr_throw must be used to ensure that this is also true for newly created errors. static maxon::Float GetRandomFloat( maxon::Float scale) { iferr_scope_handler { // is called by iferr_return or iferr_throw before it returns from the function DiagnosticOutput ( "Error: @" , err);

// defines the return value return 0.0; };

// check "scale" argument // use iferr_throw to make sure iferr_scope_handler is called if (scale == 0.0) iferr_throw (maxon::IllegalArgumentError( MAXON_SOURCE_LOCATION ));

// return if an error is returned const maxon::Int randomNumber = GetRandomNumber() iferr_return ; const maxon :: Float randomFloat = ( maxon :: Float )randomNumber / scale; return randomFloat; }

In some cases an error can be ignored. Such cases must be marked and explained explicitly:

注意
Use these attributes only if the error can be ignored or there is no way of handling the error. Always describe the reason why this macro was used.
// This example shows how an error can be ignored explicitly.

// create array and ensure capacity maxon::BaseArray<maxon::Int> numbers; numbers. EnsureCapacity (count) iferr_return ;

// fill array for ( maxon::Int i = 0; i < count; ++i) { numbers. Append (i) iferr_cannot_fail ( "Array capacity ensured" ); }

// just try to increase capacity // use the second parameter "debug" to trigger a debug stop in case of an error numbers. EnsureCapacity (newCount) iferr_ignore ( "Capacity size not important." , debug);

Error handling can be limited to a sub-scope within a function by using a lambda:

// This example limits the error handling to an lambda. // All errors returned from that lambda are handled in one point. static maxon::Float GetRandomFloat( maxon::Float scale) { // define lambda with internal error handling auto GetFloat = [scale]() -> maxon::Result<maxon::Float> { iferr_scope ; if (scale == 0.0) return maxon::IllegalArgumentError( MAXON_SOURCE_LOCATION );

// return if an error is returned const maxon::Int randomNumber = GetRandomNumber() iferr_return ; const maxon :: Float randomFloat = ( maxon :: Float )randomNumber / scale; return randomFloat; }; maxon :: Float randomFloat = 0.0;

// call lambda and handle error iferr (randomFloat = GetFloat()) DiagnosticOutput ("Error: @", err); return randomFloat; }

Error Handling and Resource Management

The attribute iferr_return allows to return from a function when an error was detected. This could lead to issues with resources that have to be managed and freed within the function scope. For example a certain resource must be freed when the function is ending. Allocated objects and memory are best handled using 参考 .

For more complex situations one can use either iferr_scope_handler or finally:

// This example shows a function that has to prepare and free internal data. // FreeInternalData() must always be called when the function is left. // iferr_scope_handler is used to ensure that FreeInternalData() is called // in the case an error is returned. static maxon::Result<void> PerformInternalTask() { iferr_scope_handler { // make sure internal data is freed when an error occurred FreeInternalData();

// print error DiagnosticOutput ( "Error: @" , err);

// return error return err; }; PrepareInternalData() iferr_return ; HandleInternalData() iferr_return ;

// check for success // use iferr_throw to make sure iferr_scope_handler is called if (GetInternalSuccess() == false) iferr_throw ( maxon ::UnexpectedError( MAXON_SOURCE_LOCATION )); StoreInternalData() iferr_return ; FreeInternalData(); return maxon :: OK ; }

// This example shows a function that has to prepare and free internal data. // FreeInternalData() must always be called when the function is left. // The "finally" macro is used to ensure that FreeInternalData() is called // when the function is left, independent of how the function is left. static maxon::Result<void> PerformInternalTask() { iferr_scope ; finally { // make sure internal data is always freed FreeInternalData(); }; PrepareInternalData() iferr_return ; HandleInternalData() iferr_return ;

// check for success if (GetInternalSuccess() == false) return maxon ::UnexpectedError( MAXON_SOURCE_LOCATION ); StoreInternalData() iferr_return ; return maxon :: OK ; }

延伸阅读

iferr_throw
#define iferr_throw(ERR)
定义: resultbase.h:1497
maxon
The maxon namespace contains all declarations of the MAXON API.
定义: c4d_basedocument.h:15
Float
maxon::Float Float
定义: ge_sys_math.h:64
maxon::Float32
float Float32
32 bit floating point value (float)
定义: apibase.h:178
maxon::OK
return OK
定义: apibase.h:2532
iferr_return
#define iferr_return
定义: resultbase.h:1434
MAXON_SOURCE_LOCATION
#define MAXON_SOURCE_LOCATION
定义: memoryallocationbase.h:66
maxon::Float
Float64 Float
定义: apibase.h:193
maxon::BaseArray
定义: basearray.h:366
DiagnosticOutput
#define DiagnosticOutput(formatString,...)
定义: debugdiagnostics.h:166
iferr_cannot_fail
#define iferr_cannot_fail(str)
定义: resultbase.h:1378
maxon::Result
定义: apibase.h:314
OK
OK
Ok.
定义: ge_prepass.h:2
MAXON_ERROR_PREALLOCATE
#define MAXON_ERROR_PREALLOCATE(errorName, init)
定义: errorbase.h:426
iferr_ignore
#define iferr_ignore(...)
定义: resultbase.h:1399
maxon::BaseArray::Append
MAXON_ATTRIBUTE_FORCE_INLINE ResultRef< T > Append()
定义: basearray.h:569
maxon::Int
Int64 Int
signed 32/64 bit int, size depends on the platform
定义: apibase.h:184
iferr_scope
#define iferr_scope
定义: resultbase.h:1343
iferr_scope_handler
#define iferr_scope_handler
定义: resultbase.h:1361
iferr
#define iferr(...)
定义: errorbase.h:380
maxon::BaseArray::EnsureCapacity
ResultMem EnsureCapacity(Int requestedCapacity, COLLECTION_RESIZE_FLAGS resizeFlags=COLLECTION_RESIZE_FLAGS::ON_GROW_RESERVE_CAPACITY)
定义: basearray.h:1188

Copyright  © 2014-2025 乐数软件    

工业和信息化部: 粤ICP备14079481号-1