From a3ad5abf2fe85d623f9e78fefc34e27bdc14632e Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Fri, 17 Dec 2021 15:38:15 +0100 Subject: Allocator: simplify using guarded allocator in C++ code Using the `MEM_*` API from C++ code was a bit annoying: * When converting C to C++ code, one often has to add a type cast on returned `void *`. That leads to having the same type name three times in the same line. This patch reduces the amount to two and removes the `sizeof(...)` from the line. * The existing alternative of using `OBJECT_GUARDED_NEW` looks a out of place compared to other allocation methods. Sometimes `MEM_CXX_CLASS_ALLOC_FUNCS` can be used when structs are defined in C++ code. It doesn't look great but it's definitely better. The downside is that it makes the name of the allocation less useful. That's because the same name is used for all allocations of a type, independend of where it is allocated. This patch introduces three new functions: `MEM_new`, `MEM_cnew` and `MEM_delete`. These cover the majority of use cases (array allocation is not covered). The `OBJECT_GUARDED_*` macros are removed because they are not needed anymore. Differential Revision: https://developer.blender.org/D13502 --- intern/guardedalloc/MEM_guardedalloc.h | 73 ++++++++++++++++++++-------------- 1 file changed, 43 insertions(+), 30 deletions(-) (limited to 'intern/guardedalloc') diff --git a/intern/guardedalloc/MEM_guardedalloc.h b/intern/guardedalloc/MEM_guardedalloc.h index 3c006b9a70c..043f7055ab1 100644 --- a/intern/guardedalloc/MEM_guardedalloc.h +++ b/intern/guardedalloc/MEM_guardedalloc.h @@ -259,6 +259,49 @@ void MEM_use_guarded_allocator(void); #endif /* __cplusplus */ #ifdef __cplusplus + +# include +# include + +/** + * Allocate new memory for and constructs an object of type #T. + * #MEM_delete should be used to delete the object. Just calling #MEM_freeN is not enough when #T + * is not a trivial type. + */ +template +inline T *MEM_new(const char *allocation_name, Args &&...args) +{ + void *buffer = MEM_mallocN(sizeof(T), allocation_name); + return new (buffer) T(std::forward(args)...); +} + +/** + * Allocates zero-initialized memory for an object of type #T. The constructor of #T is not called, + * therefor this should only used with trivial types (like all C types). + * It's valid to call #MEM_freeN on a pointer returned by this, because a destructor call is not + * necessary, because the type is trivial. + */ +template inline T *MEM_cnew(const char *allocation_name) +{ + static_assert(std::is_trivial_v, "For non-trivial types, MEM_new should be used."); + return static_cast(MEM_callocN(sizeof(T), allocation_name)); +} + +/** + * Destructs and deallocates an object previously allocated with any `MEM_*` function. + * Passing in null does nothing. + */ +template inline void MEM_delete(const T *ptr) +{ + if (ptr == nullptr) { + /* Support #ptr being null, because C++ `delete` supports that as well. */ + return; + } + /* C++ allows destruction of const objects, so the pointer is allowed to be const. */ + ptr->~T(); + MEM_freeN(const_cast(ptr)); +} + /* Allocation functions (for C++ only). */ # define MEM_CXX_CLASS_ALLOC_FUNCS(_id) \ public: \ @@ -292,36 +335,6 @@ void MEM_use_guarded_allocator(void); { \ } -/* Needed when type includes a namespace, then the namespace should not be - * specified after ~, so using a macro fails. */ -template inline void OBJECT_GUARDED_DESTRUCTOR(T *what) -{ - what->~T(); -} - -# if defined __GNUC__ -# define OBJECT_GUARDED_NEW(type, args...) new (MEM_mallocN(sizeof(type), __func__)) type(args) -# else -# define OBJECT_GUARDED_NEW(type, ...) \ - new (MEM_mallocN(sizeof(type), __FUNCTION__)) type(__VA_ARGS__) -# endif -# define OBJECT_GUARDED_DELETE(what, type) \ - { \ - if (what) { \ - OBJECT_GUARDED_DESTRUCTOR((type *)what); \ - MEM_freeN(what); \ - } \ - } \ - (void)0 -# define OBJECT_GUARDED_SAFE_DELETE(what, type) \ - { \ - if (what) { \ - OBJECT_GUARDED_DESTRUCTOR((type *)what); \ - MEM_freeN(what); \ - what = NULL; \ - } \ - } \ - (void)0 #endif /* __cplusplus */ #endif /* __MEM_GUARDEDALLOC_H__ */ -- cgit v1.2.3