During Handmade Hero days 539-541 Casey introduced INTERNAL_MEMORY_PARAM and INTERNAL_MEMORY_PASS to get the original location of memory allocations (or push commands) in source files. This inspired me to implement a similar solution to my project to detect where the allocations are called from.
For example on Handmade Hero there is a function with supporting macros:
#define DEBUG_MEMORY_NAME(name) DEBUG_NAME_(__FILE__, __LINE__, __COUNTER__), #define INTERNAL_MEMORY_PARAM char *GUID, #define INTERNAL_MEMORY_PASS GUID, #define PushBuffer(...) PushBuffer_(DEBUG_MEMORY_NAME("PushBuffer") __VA_ARGS__) static string PushBuffer_(INTERNAL_MEMORY_PARAM memory_arena *arena, umm size, arena_push_params params = DefaultArenaParams()) { buffer result; result.count = size; result.data = (uint8 *)PushSize_(INTERNAL_MEMORY_PASS arena, result.count, params); return result; }
INTERNAL_MEMORY_PARAM and INTERNAL_MEMORY_PASS are used for passing the original source of the push call.
This approach works very well with various functions. Of course there is one exception, which just happens to be one of the most common use cases in my project. There is this memory allocator class (the only class in the project), which handles some basic functionality for multidimensional data. The only internal class functions are constructors with different parameters, a destructor and some operators. Supporting functions are just handling data contents of the struct. The problem here is the constructor.
The allocator itself in allocator.h:
#define INTERNAL_MEMORY_PARAM_END ,char *GUID struct Allocator { Allocator(int xsize, int ysize, int zsize INTERNAL_MEMORY_PARAM_END) { AllocatorPush(INTERNAL_MEMORY_PASS *this, xsize, ysize, zsize); } };
If we call the constructor like
source.cpp:
Allocator xxx(6, 6, 6)
the allocated memory location is set to allocator.h not to source.cpp as I was hoping for. One of the reasons for this is that I seemingly cannot create an internal constructor (with added '_') and define the actual construct with a macro, just like it was done with functions.
I can bypass this with the following, which then shows the correct location for original allocation:
Allocator xxx; AllocatorPush(xxx, 6, 6, 6);
The problem is that the constructor allocation is the mostly used way of allocating multidimensional data and I'm trying to find a way solve this without doing the multitude of changes to code base.
Question: Is the caller location for the constructor even possible to get with preprocessor macros?
You could use a macro that would expand to the constructor with the first parameter being the GUID.
struct Allocator { Allocator( INTERNAL_MEMORY_PARAM, int x, int y, int z ) { AllocatorPush( INTERNAL_MEMORY_PASS, *this, x, y, z ); } }; #define make_allocator( name, ... ) Allocator name( __FILE__, __VA_ARGS__ ) int main( void ) { make_allocator( allocator, 1, 2, 3 ); }