C++: allocate block of T without calling constructor
Asked Answered
W

3

35

I don't want constructor called. I am using placement new.

I just want to allocate a block of T.

My standard approach is:

T* data = malloc(sizeof(T) * num);

however, I don't know if (data+i) is T-aligned. Furthermore, I don't know if this is the right "C++" way.

How should I allocate a block of T without calling its constructor?

Wattage answered 4/3, 2010 at 21:44 Comment(2)
Why don't you want to call the constructor? If it's because your constructor is doing work you don't always want to do, you might consider moving that work into a separate init() method.Gerita
For example, std::vector does this (allocating memory without yet constructing objects).Effectually
T
40

Firstly, you are not allocating a "block of T*". You are allocating a "block of T".

Secondly, if your T has non-trivial constructor, then until elements are constructed, your block is not really a "block of T", but rather a block of raw memory. There's no point in involving T here at all (except for calculating size). A void * pointer is more appropriate with raw memory.

To allocate the memory you can use whatever you prefer

void *raw_data = malloc(num * sizeof(T));

or

void *raw_data = new unsigned char[num * sizeof(T)];

or

void *raw_data = ::operator new(num * sizeof(T));

or

std::allocator<T> a;
void *raw_data = a.allocate(num);
// or
// T *raw_data = a.allocate(num);

Later, when you actually construct the elements (using placement new, as you said), you'll finally get a meaningful pointer of type T *, but as long as the memory is raw, using T * makes little sense (although it is not an error).

Unless your T has some exotic alignment requirements, the memory returned by the above allocation functions will be properly aligned.

You might actually want to take a look at the memory utilities provided by C++ standard library: std::allocator<> with allocate and construct methods, and algorithms as uninitialized_fill etc. instead or trying to reinvent the wheel.

Tobit answered 4/3, 2010 at 21:50 Comment(7)
I think std::allocator<> is the "most C++" way of doing itDistillation
How do you deallocate (calling destructors) using this method?Conation
@André Puel: You do everythng in reverse. Firstly, you manually invoke the destructors one by one (there's syntax for destructor invocation in C++). Then you just free the memory (if it was malloced), or use another appropriate raw-memory dealocation function.Tobit
My point is that bad things happens if you invoke delete[] on your T*. And if you give this T* to someone else and say "You own this T*", this someone else will probably invoke delete[]. Please include this warning in your answer.Conation
@André Puel: No. That's a totally different issue, which has nothing to do with the question as asked. It's like including warning about dangers of division by zero into every answer that even mentions division operator. The question is about some specifics of custom allocation, not about basics of custom allocation.Tobit
It is nothing like division by zero. Because if you allocate, you must deallocate. You cant tell people how to allocate without telling how to deallocate. Why do you consider "You can't use delete[] in your custom allocated array" a basic concept?Conation
@AndréPuel can you elaborate on the "bad things" that happen? Do they still happen for the version using "::operator new(num * sizeof(T));" ?Renowned
E
7

The return from malloc is aligned for any type, so that's not a problem.

Generally in C++, ::operator new would be the preferred way. You might also consider using an Allocator<T>, which gives some extra flexibility (like being able to switch allocators easily.

Ewell answered 4/3, 2010 at 21:47 Comment(0)
E
0

T* data = reinterpret_cast<T*>(operator new(sizeof(T) * num));

Or just use std::vector<T> and don't worry about these low-level memory details ;)

Evans answered 4/3, 2010 at 21:57 Comment(2)
I think if T is not a POD type then this leads to undefined behavior.Logos
vector will invoke the default constructors for each T.Nahuatlan

© 2022 - 2024 — McMap. All rights reserved.