------- Comment #8 from jima at cadence dot com 2007-03-21 20:58 ------- I tried using placement-new and explicit destructor calls to delineate the lifetime of the allocator's internal class objects explicitly, such that their lifetimes do not overlap with any references to the same storage via pointers of other types (that is, during the lifetime of the high-level object being allocated).
Can someone point out why this doesn't work? See the following program ... #include <stdio.h> #include <stdlib.h> #include <new> struct Block { Block * next; char rest_of_storage[128-sizeof(Block *)]; // max obj sizeof is 128 }; static Block * free_head = 0; class C { public: void * operator new(size_t bytes_needed) { if (free_head == 0) { abort(); } Block * storage = free_head; free_head = storage->next; // Explicitly call the destructor for Block 'storage' to end its lifetime. // (cf C++ 06 draft @12.4-13). C++ says the lifetime of the new 'C' being // allocated begins when its constructor is called, which has not yet // happened. Therefore the lifetimes of the Block and the C it is // aliased to do not overlap, so the compiler should not re-order // references to pass this barrier point. storage->~Block(); return storage; } void operator delete(void * ptr_to_free, size_t how_big_it_is) { // The lifetime of the C ended at start of its destructor, which occurred // before we get here. So references to the C should not be re-ordered // to pass that previous point (the start of its destructor). // The following placement-new begins the lifetime of Block 'storage'. // Therefore accesses to the old C and the new Block should not mix up. Block * storage = new(ptr_to_free) Block; storage->next = free_head; free_head = storage; // The lifetime of the Block 'storage' continues until it is ended // in a later call to operator new. } C() {} virtual ~C() {} // virtual dtor required for problem to appear (why?) }; int main() { setbuf(stdout,NULL); setbuf(stderr,NULL); // disable buffering free_head = new Block; // Put one object on the free-list free_head->next = 0; C *obj = new C; delete obj; if (free_head->next != 0) { printf("ERROR: Expected only one block on free list\n"); return 1; } return 0; } -- http://gcc.gnu.org/bugzilla/show_bug.cgi?id=31289