Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's wrong with this use of placement new[]? do

Consider the program below. It has been simplified from a complex case. It fails on deleting the previous allocated memory, unless I remove the virtual destructor in the Obj class. I don't understand why the two addresses from the output of the program differ, only if the 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 the virtual destructor is present:

Allocated memory address starts at: 0x8895008 The memory to be deallocated starts at: 0x889500c

RUN FAILED (exit value 1)

Please don't ask what the program it's supposed to do. As I said it comes from a more complex case where Arena is an interface for various types of memory. In this example the memory is just allocated and deallocated from the heap.

like image 445
Martin Avatar asked Nov 24 '11 20:11

Martin


People also ask

What does the placement new do?

Placement new is a variation new operator in C++. Normal new operator does two things : (1) Allocates memory (2) Constructs an object in allocated memory. Placement new allows us to separate above two things. In placement new, we can pass a preallocated memory and construct an object in the passed memory.

Does placement New allocate memory?

Because placement new does not allocate memory, you should not use delete to deallocate objects created with the placement syntax. You can only delete the entire memory pool ( delete whole ). In the example, you can keep the memory buffer but destroy the object stored in it by explicitly calling a destructor.

Does placement new call destructor?

An explicit call to destructor is only necessary when an object is placed at a particular location in memory by using placement new. Destructor should not be called explicitly when the object is dynamically allocated because the delete operator automatically calls destructor.

Which of the following is the correct way to use new operator?

Which among the following is added in grammar of new operator? Explanation: The new operator grammar is added with an initializer field. This can be used to initialize an object with a user defined constructor.


1 Answers

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

OK, the spec makes it clear:

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

2.7 Array Operator new Cookies

When operator new is used to create a new array, a cookie is usually stored to remember the allocated length (number of array elements) so that it can be deallocated correctly.

Specifically:

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

So, the virtual-ness of the destructor is irrelevant, what matters is that the destructor is non-trivial, which you can easily check, by deleting the keyword virtual in front of the destructor and observe the program crashing.

like image 76
chill Avatar answered Sep 28 '22 23:09

chill