I understand we can use Class-specific overloads of operator new[]/delete[] to specify our own memory allocation strategy.
So I write the following code. I barely want to use the held field to record how much memory of a type X<id> is allocated on heap.
However, I meet the problem that in operator new[], I can get the count, while I can’t in operator delete[]. So in operator delete[], I don’t know how much memory is actually released.
#include <cstdio>
#include <string>
#include <vector>
template <int Id>
struct X {
static inline int held = 0;
static void* operator new(std::size_t count)
{
held += count;
return ::operator new(count);
}
static void* operator new[](std::size_t count)
{
held += count;
return ::operator new[](count);
}
static void operator delete(void* ptr)
{
held -= sizeof(X<Id>);
::operator delete(ptr);
}
static void operator delete[] (void* ptr)
{
// This is not correct.
// However, I don't know the count.
held -= sizeof(X<Id>);
::operator delete [] (ptr);
}
std::string s1;
std::vector<int> v1;
};
int main() {
auto * dx2 = new X<1>[100]();
printf("x1d2 %d\n", X<1>::held);
delete [] dx2;
printf("x1d2 released %d\n", X<1>::held); // exptected 0
}
I understand one way is that I can allocate an extra bytes to store the count, it introduces extra overhead though.
Moreover, the compiler will actually store the count somewhere when compiling operator delete [], however, it is not exposed to users. I think I am now allowed to access the count.
>Solution :
Since C++14, there are flavors of operator delete (number (5)) and operator delete[] (number (6)), that you can override and have an additional parameter for the allocated size:
void operator delete ( void* ptr, std::size_t sz ) noexcept; (5)
void operator delete[] ( void* ptr, std::size_t sz ) noexcept; (6)
These operators have priority over the ones without the size:
Called instead of (1,2) if a user-defined replacement is provided,
In your case you can replace your operator delete and operator delete[] with:
static void operator delete(void* ptr, std::size_t sz)
{
held -= sz;
::operator delete(ptr);
}
static void operator delete[](void* ptr, std::size_t sz)
{
held -= sz;
::operator delete[](ptr);
}
Output on MSVC (last value is 0 as expected):
x1d2 7208
x1d2 released 0
Some notes:
heldshould better be asize_tto match the type in thenewanddeleteoperators.- My live demo is using
std::coutinstead of the less-recommnded C styleprintfs. - In the live demo
heldhas different values after the allocation in different compilers because the size of classes is implementation dependant (but it is always 0 after deallocation).