What is wrong with this use of the new [] placement? do

Consider the program below. It was simplified from a difficult case. It does not delete the previous allocated memory unless I delete the virtual destructor in the Obj class. I do not understand why the two addresses from the output of the program differ only if a virtual destructor is present.

// GCC 4.4 #include <iostream> using namespace std; class Arena { public: void* alloc(size_t s) { char* p = new char[s]; cout << "Allocated memory address starts at: " << (void*)p << '\n'; return p; } void free(void* p) { cout << "The memory to be deallocated starts at: " << p << '\n'; delete [] static_cast<char*> (p); // the program fails here } }; struct Obj { void* operator new[](size_t s, Arena& a) { return a.alloc(s); } virtual ~Obj() {} // if I remove this everything works as expected void destroy(size_t n, Arena* a) { for (size_t i = 0; i < n; i++) this[n - i - 1].~Obj(); if (a) a->free(this); } }; int main(int argc, char** argv) { Arena a; Obj* p = new(a) Obj[5](); p->destroy(5, &a); return 0; } 

This is the output of the program in my implementation when a virtual destructor is present:

The allocated memory address starts with: 0x8895008 The memory to be freed begins with: 0x889500c

RUN FAILED (output value 1)

Please do not ask what program he should do. As I said, this comes from a more complex case where Arena is the interface for various types of memory. In this example, the memory is simply allocated and freed from the heap.

+7
source share
2 answers

this not the pointer returned by new in the string char* p = new char[s]; . You can see that the size s exceeds 5 Obj instances. The difference (which should be sizeof (std::size_t) ) is in extra memory containing the length of the array, 5, immediately before the address contained in this .

OK, the specification makes it clear:

http://sourcery.mentor.com/public/cxx-abi/abi.html#array-cookies

2.7 new cookie array operators

When the new operator is used to create a new array, the cookie is usually saved to remember the selected length (the number of elements in the array) so that it can be freed correctly.

In particular:

No cookie is required if the element type of array T has a trivial destructor (12.4 [class.dtor]), and the regular (array) deallocation function (3.7.3.2 [basic.stc.dynamic.deallocation]) do not take two arguments.

So, the virtuality of the destructor does not matter, it is important that the destructor is nontrivial, which you can easily check by removing the virtual in front of the destructor and observing the program crash.

+5
source

Based on the answer to chills, if you want to make it β€œsafe”:

 #include <type_traits> a->free(this - (std::has_trivial_destructor<Obj>::value ? 1 : 0)); 
0
source

All Articles