@@ -333,10 +333,8 @@ add_library(celix::MyBundle ALIAS MyBundle)
333333- Use ` while ` statements for loops that may not execute.
334334- Use ` do ` /` while ` statements for loops that must execute at least once.
335335- Use ` for ` statements for loops with a known number of iterations.
336- - The use of ` goto ` is not allowed, except for error handling in C (for C++ use RAII).
337- - For C, try to prevent deeply nested control structures and prefer early returns or error handling ` goto ` statements.
338- - To prevent deeply nested control structures, the ` CELIX_DO_IF ` , ` CELIX_GOTO_IF_NULL ` and ` CELIX_GOTO_IF_ERR `
339- macros can also be used.
336+ - Avoid using ` goto ` for error handling. Prefer early returns and automatic cleanup using celix auto pointers.
337+ - To prevent deeply nested control structures, the ` CELIX_DO_IF ` macro can also be used.
340338
341339## Functions and Methods
342340
@@ -350,7 +348,7 @@ add_library(celix::MyBundle ALIAS MyBundle)
350348- For C++ functions with a lot of different parameters, consider using a builder pattern.
351349 - A builder pattern can be updated backwards compatible.
352350 - A builder pattern ensure that a lot of parameters can be configured, but also direct set on construction.
353-
351+
354352## Error Handling and Logging
355353
356354- For C++, throw an exception when an error occurs and use RAII to ensure that resources are freed.
@@ -362,9 +360,10 @@ add_library(celix::MyBundle ALIAS MyBundle)
362360- Use consistent error handling techniques, such as returning error codes or using designated error handling functions.
363361- Log errors, warnings, and other important events using the Apache Celix log helper functions or - for libraries -
364362 the ` celix_err ` functionality.
365- - Always check for errors and log them.
363+ - Always check for errors and log them.
366364- Error handling should free resources in the reverse order of their allocation/creation.
367365- Ensure error handling is correct, using test suite with error injection.
366+ - Prefer early returns together with celix auto pointers to ensure cleanup without using ` goto ` .
368367
369368For log levels use the following guidelines:
370369- trace: Use this level for very detailed that you would only want to have while diagnosing problems.
@@ -381,37 +380,47 @@ For log levels use the following guidelines:
381380- fatal: Use this level to report severe errors that prevent the program from continuing to run.
382381 After logging a fatal error, the program will typically terminate.
383382
384- Example of error handling and logging:
383+ Example of error handling and logging using auto pointers :
385384``` c
385+ typedef struct celix_foo {
386+ celix_thread_mutex_t mutex;
387+ celix_array_list_t* list;
388+ celix_long_hash_map_t* map;
389+ } celix_foo_t ;
390+
391+ CELIX_DEFINE_AUTOPTR_CLEANUP_FUNC (celix_foo_t, celix_foo_destroy)
392+
386393celix_foo_t* celix_foo_create(celix_log_helper_t* logHelper) {
387- celix_foo_t* foo = calloc(1, sizeof(* foo));
394+ celix_autofree celix_foo_t* foo = calloc(1, sizeof(* foo));
388395 if (!foo) {
389- goto create_enomem_err;
396+ celix_logHelper_log(logHelper, CELIX_LOG_LEVEL_ERROR,
397+ "Error creating foo, out of memory");
398+ return NULL;
390399 }
391-
392- CELIX_GOTO_IF_ERR(create_mutex_err, celixThreadMutex_create(&foo->mutex, NULL));
393-
394- foo->list = celix_arrayList_create();
395- foo->map = celix_longHashMap_create();
396- if (!foo->list || !foo->map) {
397- goto create_enomem_err;
400+
401+ if (celixThreadMutex_create(&foo->mutex, NULL) != CELIX_SUCCESS) {
402+ celix_logHelper_log(logHelper, CELIX_LOG_LEVEL_ERROR,
403+ "Error creating mutex");
404+ return NULL; //foo cleaned up automatically (celix_autofree will call free)
398405 }
399406
400- return foo;
401- create_mutex_err:
402- celix_logHelper_log(logHelper, CELIX_LOG_LEVEL_ERROR, "Error creating mutex");
403- free(foo); //mutex not created, do not use celix_foo_destroy to prevent mutex destroy
404- return NULL;
405- create_enomem_err:
406- celix_logHelper_log(logHelper, CELIX_LOG_LEVEL_ERROR, "Error creating foo, out of memory");
407- celix_foo_destroy(foo); //note celix_foo_destroy can handle NULL
408- return NULL;
407+ celix_autoptr(celix_thread_mutex_t) mutex = &foo->mutex;
408+ celix_autoptr(celix_array_list_t) list = celix_arrayList_create();
409+ celix_autoptr(celix_long_hash_map_t) map = celix_longHashMap_create();
410+ if (!list || !map) {
411+ celix_logHelper_log(logHelper, CELIX_LOG_LEVEL_ERROR,
412+ "Error creating foo, out of memory");
413+ return NULL; //foo, list and/or map are cleaned up automatically
414+ }
415+
416+ celix_steal_ptr(mutex);
417+ foo->list = celix_steal_ptr(list);
418+ foo->map = celix_steal_ptr(map);
419+ return celix_steal_ptr(foo);
409420}
410421
411422void celix_foo_destroy(celix_foo_t* foo) {
412- if (foo != NULL) {
413- //note reverse order of creation
414- celixThreadMutex_destroy(&foo->mutex);
423+ if (foo) {
415424 celix_arrayList_destroy(foo->list);
416425 celix_longHashMap_destroy(foo->map);
417426 free(foo);
0 commit comments