Search code examples
c++vectorplacement-new

Using placement new in a Vector Container


If I have a container:

std::vector<T*> elements;

can I use placement new to allocate my objects so that the objects are all allocated contiguously? So that I can do something like this:

size_t elementIndex = someRandomElement - elements[0];

Where someRandomeElement is a random element from elements and elementIndex will then store the correct index of someRandomElement so that elements[elementIndex] == someRandomElement

This is needed for my current implementation of a memory manager. I have an implementation that I was able to finish today, but it requires the elements (which can be a voxel, a triangle or anything else) to have GetIndex() and SetIndex() function so that when the element is returned as a pointer, I can find out the index of the element in the elements array, which means that any elements that I cannot change (let's say Ogre::Vector3) cannot use the manager (in my case, I need them to use it because they are fragmenting the memory).

My only other solution is to have a structure that acts as an accessor and has the index as well as the pointer to the element although this will result in an increased memory usage (considering I am working with 5 million elements right now).

NOTE: There is a similar question that I posted today, but the answers there are making some assumptions which go totally against my requirements. One of the requirement is that the vector must be filled with pointers to T otherwise a large portion of the code-base needs to change. Secondly, initializing more than 100,000 (approximately) elements results in a bad_alloc exception. Each element is 196 bytes in size (I have managed to reduce that to 132 bytes).


Solution

  • To make your pointed-to objects contiguous, you have two reasonable options:

    • use new[] to create a single array of elements big enough to hold them all, then assign new values into them and put their addresses into elements
    • use malloc() to create a big enough uninitialised memory area to hold them all (it will likely be sufficiently-strictly aligned, but you should be aware of the issue), then use placement new to construct your elements in that memory

    Do not use new[] then placement new, as the default-constructed element won't be destructed before placement new overwrites their memory... consequently any resources their constructor takes, counters it maintains etc. can't be properly released/updated by the destructor.

    If you don't have enough memory to allocate the big array, then obviously you can't do it... simple as that. 100,000 separate new Ts can be expected to need more memory than a single new T[100000] though... there's padding and heap management overheads associated with allocation.