1

Hello So I'm experimenting with creating objects and arrays with preallocated memory. For instance I have this following code:

int * prealloc = (int*)malloc(sizeof(Test));

Test *arr = new(prealloc) Test();

Where test is defined as follows:

class Test {
public:
    Test() {
        printf("In Constructor\n");
    }
    ~Test() {
        printf("In Destructor\n");
    }

    int val;
};

In this scenario if I call delete it will actually release the memory which is bad, b/c maybe I'm using some type of memory manager so this will sure cause some problems. I searched in the internet and the only solution that I found was to call the destructor explicitly and then call free:

arr->~Test();
free(arr);

Is there another way to do this? is there perhaps a way to call delete and tell it to just call the destructor and not to release the memory?

My second problem was when working with arrays, like the previous example you can pass to new the pre-allocated memory:

int * prealloc2 = (int*)malloc(sizeof(Test) * 10);
Test *arr2 = new(prealloc2) Test[10];

If I call delete[] it will not only call the destructor for each element in the array but it will also release the memory which is something I don't want. The only way I have found that it should be done is to go through the array and call the destructor explicitly, and then call free. Like with the regular none array operators is there a way to tell the operator to just call the destructors without releasing the memory?

One thing I did notice was that the new operator for an array will actually use the first 4 bytes to store the size of the array (I only tested this in visual studio with a 32 bit build) That would help me know how many elements the array has but there is still one problem. What if the array is a pointer array? for example:

Test **arr2 = new Test*[10];

Could someone help me out with these questions please.

Kunashu
  • 268
  • 1
  • 4
  • 14
  • Why not overload the `new` and `delete` operators so you can allocate memory however you want? – user1520427 May 22 '13 at 23:40
  • 1
    I really didn't think about overloading them b/c I was thinking that the guy who instantiates the class should be the one to determine how the memory should be maped. – Kunashu May 23 '13 at 00:20
  • [Don't placement new an array into a preallocated buffer](http://stackoverflow.com/questions/8720425/array-placement-new-requires-unspecified-overhead-in-the-buffer) – Mooing Duck May 23 '13 at 00:35
  • @Kunashu You could use a template policy as described in Modern C++? – user1520427 May 23 '13 at 02:31

3 Answers3

5

It's normal and expected to directly invoke the destructor to destroy objects you've created with placement new. As far as any other way to do things, about the only obvious alternative is to use an Allocator object (which, at least 99% of the time, will just be a wrapper around placement new and directly invoking the destructor).

Generally speaking, you do not want to use new[] at all. You typically want to allocate your raw memory with operator new (or possibly ::operator new) and release it with the matching operator delete or ::operator delete.

You create objects in that memory with placement new and destroy them by directly invoking the destructor.

Jerry Coffin
  • 437,173
  • 71
  • 570
  • 1,035
  • Ok I think the route I will have to choose is to create a wrapper allocator. The thing is that b/c Im doing games I would prefer to use a custom allocator to know for any memory leaks. The only question that I have is why should I not use `new[]` operator? – Kunashu May 23 '13 at 00:17
  • 1
    @Kunashu: Basically, because `new[]` is sort of a useless halfway point between allocating raw memory and using a real container (like you're apparently trying to write, or a `std::vector`, `std::deque`, etc.) It ends up doing too much to be a good raw allocator, but not enough to be a good container. – Jerry Coffin May 23 '13 at 00:22
  • So if I want to make my own container you recommend me use malloc instead of new? Like you said that is what Im really looking to do. To make a container class but, I wanted to add the possibility to plug in some custom allocator through the use of policies. – Kunashu May 23 '13 at 00:25
  • @Kunashu: if you're writing your own container, use `new char[size]` instead of malloc. Or better yet, just use an allocator like `vector` and friends. But don't placement new an array. – Mooing Duck May 23 '13 at 00:37
  • @Kunashu: No, as mentioned in my answer, to allocate raw memory you want to use `operator new` or `::operator new`. – Jerry Coffin May 23 '13 at 00:37
  • A ok after what you mentioned about the `::operator new` I searched the internet and found this [link](http://stackoverflow.com/questions/4941793/new-operator-for-memory-allocation-on-heap) And now I get what you meant by callig the `::operator new` Thanks again for your help :D – Kunashu May 23 '13 at 00:44
  • 1
    @Kunashu: Oops -- sorry. Another link I think is worth reading: http://stackoverflow.com/a/7151831/179910 (though I may be biased). – Jerry Coffin May 23 '13 at 01:27
2

There is no other way to do it but to explicitly call the destructor as delete will also attempt to free the memory.

Using preallocated memory with placement new should be fairly rare in your code - a typical use case is when you're dealing with direct memory mapped hardware interfaces when you want/need to map an object on top of a fixed memory address - and is something I'd normally consider a code smell.

If you want to tweak the memory management for a specific class, you're much better off either using an STL container with a custom allocator or overload operators new and delete for that specific class.

Timo Geusch
  • 23,267
  • 4
  • 48
  • 70
  • placement new in preallocated memory is quite common for containers though. – Mooing Duck May 23 '13 at 00:47
  • Fair point, I should have elaborated that its use in "normal", ie implementation code is what I'd consider a code smell apart from a few exceptions. – Timo Geusch May 23 '13 at 02:51
0

Yes, this is the only way to do it. There is an asymmetry in being allowed to define new but not delete. [ Well, you can do the latter but it can only get called when new throws an exception (not handled properly below!)

You can use a templated destroy to achieve the same result:

class Test 
{
public:
    Test() {
        printf("In Constructor\n");
    }
    ~Test() {
        printf("In Destructor\n");
    }

    int val;
};

class Allocator
{
public:
    static void* allocate(size_t amount) { return std::malloc(amount);}
    static void unallocate(void* mem) { std::free(mem);}
    static Allocator allocator;
};

Allocator Allocator::allocator;

inline void* operator new(size_t size,  const Allocator& allocator)
{
    return allocator.allocate(size);
}


template<class T>
void destroy(const Allocator& allocator, T* object) 
{ 
    object->~T();
    allocator.unallocate(object);
}




int main()
{
    Test* t = new (Allocator::allocator) Test();

    destroy(Allocator::allocator, t);

    return 0;
}
Keith
  • 6,536
  • 16
  • 22
  • You wrote an object called `Allocator` that doesn't even remotely fullfill the `allocator` concept? http://en.cppreference.com/w/cpp/concept/Allocator – Mooing Duck May 23 '13 at 00:48
  • OK, not the right name. In real code, the core `Allocator` as above would have a name reflecting its actual memory pool type (presumably not `malloc/free`), and I'd define a full C++ Allocator using a template instantiated based on something on the lines of the above. My point is that the `destroy` template can replace the usual `delete`. – Keith May 23 '13 at 02:41