I have been working on creating a custom allocator as a fun exercise/practice and I ran into two potentials issues with creating arrays. For a typical call for allocation, I will use malloc and placement new. However, when I go to create an array I am confused on how it should be done. For once, I have noticed at some places that it seems placement new may not be safe for arrays such as here. I am also running into an error of my own while attempting to use placement new for an array. I will get the error of
`error C2679: binary ‘=’ : no operator found which takes a right-hand operand of type ‘SomeClass *’ (or there is no acceptable conversion)
I understand the error (I believe) but I would prefer to have the error be solved via my array construction method. I have two questions
1) How can an allocator create an array without using new[]? Is it with placement new? If so, what about the potential dangers mentioned from the link I posted above?
2) If I am suppose to use placement new and call it on each one of the elements in the array, why am I getting the error mentioned above?
#include <stdio.h>
#include <new>
class SomeClass{
public:
SomeClass() {
printf("Constructed\n");
}
~SomeClass() {
printf("Destructed\n");
}
};
void* SomeAllocationFunction(size_t size) {
return malloc(size);
}
template<typename Type>
Type* SomeArrayAllocationFunction(size_t count){
Type* mem = (Type*)SomeAllocationFunction(sizeof(Type) * count);
for(unsigned int i = 0; i < count; ++i)
{
mem[i] = new(mem + i) Type();
}
return mem;
}
int main(void){
SomeClass* t = SomeArrayAllocationFunction<SomeClass>(2);
}
The problem in the link is misunderstanding how things work. Each implementation has an implementation defined means to record information about an allocated array. This information is not required with single objects, because it is managed by the client via the implementation of
delete.With an array, the implementation must record things such as element count, destructor to call (if applicable), element size… this stuff is often stored at the start of the returned allocation, and the implementation obviously offsets the size of the allocation request appropriately. Thus, the actual size is offset in order to accommodate these hidden values. This is why
malloc(sizeof...)will not work unless your allocator does additional bookkeeping (which, btw,std::allocatorand collections interfaces bring).To record this information correctly, you could define
static void* operator new[]. To incorporate your own allocator in this scheme via placement, you could use the following approach:note that you would similarly implement placement
operator delete[]if your allocator may throw.if you want your allocator to do some bookkeeping, it gets messy. personally, i don’t think this situation is implemented well by the language, especially since array initialization was not implemented well. there will always be an additional step to perform near construction or destruction, or some globally accessible data to use in this context.
you’d need to explicitly construct elements if you’re creating an allocator which does not go through
operator new/operator new[]. extending the above example, you would want a destroy method which calleddelete[], then toldthisto free/reuse the memory (rather than the use offreeabove).if you just want a quick solution, you wll need to lug the destructor, size, and element count around with the allocation or allocator. in that scenarion, you do not use
new[]/delete[].Edit
and if you want to manage the books yourself, here’s one approach (which could go many directions):
Demo: