Previous header: \"Must I replace global operators new and delete to change memory allocation strategy in third party code?\"
Short story: We need t
Without being able to modify the library's source code - or, better, being able to influence the author of the library to modify it - I'd say you're out of luck.
There are some things the library potentially can do (even unintentionally) to make it immune to any strategy you might employ - or, in worst cases, have the result that your usage would make the library unstable or it might make your program unstable. Such as using its own custom allocators, providing its own versions of global operator new()
and operator delete()
, overriding those operators in individual classes, etc.
A strategy which would probably work is to work with the library vendor and make some modifications. The modifications (from your end) would amount to being able to initialise the library by specifying allocators it uses. For the library the effort is potentially significant (having to touch all functions that dynamically allocate memory, that use standard containers, etc) but not intractable - use the supplied allocators (or sensible defaults) throughout their code.
Unfortunately, that is at odds with your requirement to not modify the library - I am skeptical of the chances of satisfying that, particularly within constraints you have outlined (memory-thirsty, hosted on windows/linux, etc).
Cant be done for allocation made within that class library but you can use placement new to allocate classes from that third party library i.e. you can allocate the memory and have constructors of those classes called on the allocated memory.So this way even if the class has its own new operator it wouldnt get called .Howvwer , inside the class operations memory allocations to unexposed internal classes or primitives will be done using the allocation scheme of the third party library ; that cant be changed unless third party library allows you to specify an allocator like stl containers
Ugh, my sympathy. This is going to depend a lot on your compiler, your libc, etc. Some rubber-meets-road strategies that have "worked" to varying degrees for us in the past (/me braces for downvotes) are:
operator new
/ operator delete
overloads you suggested -- although note that some compilers are picky about not having throw()
specs, some really want them, some want them for new but not for delete, etc (I have a giant platform-specific #if
/#elif
block for all of the 4+ platforms we're working on now).malloc
(but not always).malloc
, calloc
, realloc
, and free
and getting your linker args in the right order so that the overrides take place (this is what gcc recommends these days, although I've had situations where it was impossible to do, and I had to use deprecated __malloc_hook
) -- again, new
and delete
tend to be implemented in terms of these, but not always.operator new
, malloc
, etc) in "our code" and using custom functions instead -- not very easy with existing codebase.Please note that this is not an answer in terms of what the standards say should happen, just my experience. I've worked with more than a few buggy/broken compilers and libc implementations in the past, so YMMV. I also have the luxury of working on fairly "sealed systems", and not being all that worried about portability for any specific application.
Regarding dynamic libraries: I'm currently in a bit of a pinch in this regard myself; our "app" gets loaded as a dynamic .so
and we have to be pretty careful to pass any delete
/free
requests back to the default allocator if they didn't come from us. The current solution is to just cordon off our allocations to a specific area: if we get a delete/free from within that address range, we dispatch to our handler, otherwise back to the default... I've even toyed with (horrors) the idea of checking the caller address to see if it's in our address space. (The probability of going boom increases with such hacks, though.)
This may be a useful strategy even if you are the process lead and you're using an outside library: tag or restrict or otherwise identify your own allocs somehow (even going so far as to keep a list of allocs you know about), and then pass on any unknowns. All of this has ugly side-effects and limitations, though.
(Looking forward to other answers!)