You need to define a class-specific operator new
. This works for me, but beware of alignment, derived classes sizes, and allocation overhead issues in the count/sizeof(MyClass)
expression:
#include <iostream>
#include <memory>
#include <new>
struct MyClass {
int dummy[8];
void *operator new[](std::size_t count) {
std::cout << "allocating " << count << " bytes, " << ((count-sizeof(void*))/sizeof(MyClass)) << " items\n";
return ::operator new[](count);
}
};
int main() {
auto x = std::make_unique<MyClass[]>(10);
}
(prints: allocating 10 items
) I think one can determine the exact overhead for your compiler/stdlib combination empirically by doing something like:
#include <iostream>
#include <memory>
#include <new>
struct MyClass {
char c;
char d;
virtual ~MyClass() {} // needed for introducing overhead
void *operator new[](std::size_t count) {
void *p = ::operator new[](count);
std::cout << "allocating " << count << " bytes\n";
return p;
}
};
int main() {
for( auto count : { 1, 5, 10, 20 } ) {
std::cout << "allocating " << sizeof(MyClass) << " * " << count << " items\n";
auto x = new MyClass[count];
delete[] x;
}
}
This will print, in my machine (and on Coliru):
allocating 16 * 1 items allocating 24 bytes, 1 items allocating 16 * 5 items allocating 88 bytes, 5 items allocating 16 * 10 items allocating 168 bytes, 10 items allocating 16 * 20 items allocating 328 bytes, 20 items
So, our count/sizeof(MyClass)
(here) should be something like
(count-sizeof(void*))/sizeof(MyClass)
But YMMV, etc.
LAST EDIT (I hope)
I had success on 64-bits linux (clang-3.4, clang-3.5 & gcc-4.8, libstdc++ & libc++) with the following how_many_elements
function:
template<class T>
std::size_t how_many_elements(std::size_t bytes) {
return (bytes -
((!std::is_trivially_destructible<T>::value)*sizeof(void*))
) / sizeof(T);
}
So your operator new
becomes something like:
void *operator new[](std::size_t count) {
std::cout << "allocating " << count << " bytes, " << how_many_elements<MyClass>(count) << " items\n";
return ::operator new[](count);
}
But I have not tested it in 32-bits environments and the YMMV still applies. And remember to replicate the operator new
for every derived class of MyClass
, obviously replacing MyClass
for MyDerivedClass
or whatever...