I want to redefine new and delete operators to use a custom allocator in a c++ project with multiple translation units. Here are the redefines written in the memops.hpp file:
#pragma once
#include "../lib/mem.h"
void* operator new(size_t size) {
return __mem_alloc(size);
}
void operator delete(void *ptr) {
__mem_free(ptr);
}
void* operator new[](size_t size) {
return __mem_alloc(size);
}
void operator delete[](void *ptr) {
__mem_free(ptr);
}
My question is where to include this header file, does it make a difference? Is the alternative definition applied every where in the project?
I found this article https://www.ibm.com/docs/en/i/7.4?topic=heap-overloading-new-delete-operator, but the last paragraph confuses me.
Where you include memops.hpp with custom allocaters matter, depending on how you are redefining the global new and delete operators.
In C++, when you define global operator new/operator delete in a translation unit, those become the global operators for the whole program - if and only if those are the ones linked into the final executable.
However, you should keep in mind that if you put this definition in a header and include it in multiple .cpp files, you’ll get multiple definitions — violating the One Definition Rule (ODR).
In addition, I would suggest you only declare methods in header file and write implementation in the single .cpp file.
Hence, memops.hpp will look like this:
#pragma once
#include <cstddef>
void* operator new(size_t size);
void operator delete(void* ptr) noexcept;
void* operator new[](size_t size);
void operator delete[](void* ptr) noexcept;
And memops.cpp:
#include "memops.hpp"
#include "../lib/mem.h"
void* operator new(size_t size) {
return __mem_alloc(size);
}
void operator delete(void* ptr) noexcept {
__mem_free(ptr);
}
void* operator new[](size_t size) {
return __mem_alloc(size);
}
void operator delete[](void* ptr) noexcept {
__mem_free(ptr);
}
This way, global overloads are defined exactly once, so linker will apply them to all uses of new and delete across your program - as long as no other translation unit provides different definition.
About the last paragraph in the article, I think, this applies mostly in the context of shared libraries. where global symbols may not propagate to other modules unless explicitly linked or included. In standard C++ projects, especially with static linking, defining the overloads in one translation unit is enough.