tags:

views:

120

answers:

2

I have a very large, spread out class that is essentially a very contrived two dimensional linked list. I want to be able to "compile" it, by which I mean I want to finalize the list, so that only read accesses may be made, and then move all the elements into contiguous memory spaces. My rough solution is this:

#include <new>
...
MyListNode* pool = new MyListNode[length];
new(&pool[position]) MyListNode();

The trouble is that I essentially have two classes, one allocated with new and the other allocated with this method up here, and when I try to delete any of the objects allocated by the above method, glibc kills the program because of an invalid pointer.

The natural solution is to create two classes, and just use runtime polymorphism to provide one interface but two implementation, etc. Is there any way that the memory standard in C++ permits this kind of jiggery pokery?

+3  A: 

The obvious possibility would be to check the address of the object, and only delete it if if falls outside your pool. If I were doing it, I think I'd probably overload operator new for the class, and have it always allocate space from your pool. This way you get your contiguous allocation without copying, and your objects are allocated uniformly so you can delete them uniformly as well.

Jerry Coffin
+2  A: 

Are you calling delete on one of the objects in your array? Or are you manually invoking the destructor to mirror the placement new?

Since you have one call to non-placement new, you should only have one call to delete. And since you have n-calls to placement-new, you should manually invoke the destructor n times.

So, you may want something like this:

// Allocate an array of chars instead of an array of MyListNode.  Since we
// are going to use placement new, this is necessary if MyListNode has a
// a default constructor
MyListNode* pool = static_cast<MyListNode *>(new char[sizeof(MyListNode) * length);
for (size_t position = 0; position < length; ++position)
    new(&pool[position]) MyListNode();

...

for (position = 0; position < length; ++position)
    pool[position].~MyListNode()

delete[] static_cast<char *>(pool);
R Samuel Klatchko
This causes undefined behaviour. `delete[] pool` is incorrect because `pool` has type `MyListNode*` but the original array was allocated as an array of `char`. Also, the `MyListNode` destructors have already been called explicitly in the previous for loop. `operator delete[]` would be the correct function to use to deallocate the memory.
Charles Bailey
@CharlesBailey - thanks. I decided to fix by casting to `char *` to mirror the allocation.
R Samuel Klatchko
Sorry, my comment was incomplete. I meant that you should use `operator new[]` to allocate as well although I didn't explicitly state that. The issue that I have with your approach is that technically you've already ended the lifetime of the `char` objects by reusing their storage for a different type of object. This is why I favour the raw storage functions approach.
Charles Bailey