The following code will construct array of 10 Foo objects with default Foo constructor:
Foo foo[10];
but i don't want do this, i have havy foo constructor and later i will regenarate all foo objects one by one and assign (copy) it to elements of foo array, so there is no sense to initialize array, i want just reserve space for it and set it elements later. Just like in the case of
int foo[10]
when elements of foo will not be initialized without ={}. How can i do this without using std namespace(i will use code both on PC and CUDA that isn't supports std)?
You can do what all good dynamic containers do: separate memory allocation and object construction.
// allocate memory
char * space[10 * sizeof(Foo)];
// make sure it's aligned for our purposes
// see comments; this isn't actually specified to work
assert(reinterpret_cast<uintptr_t>(space) % alignof(Foo) == 0);
// populate 4th and 7th slots
Foo * p = ::new (space + 3 * sizeof(Foo)) Foo('x', true, Blue);
Foo * q = ::new (space + 6 * sizeof(Foo)) Foo('x', true, Blue);
// ...
// clean up when done
q->~Foo();
p->~Foo();
The tricky part when using automatic storage is to get storage aligned at an address suitable for the alignment of the array element type. There are several ways to accomplish this; I'll elaboate on them in the future:
std::align
(thanks to @Simple):
char large_space[10 * sizeof(Foo) + 100];
std::size_t len = sizeof large_space;
void * space_ptr = large_space;
Foo * space = static_cast<Foo *>(std::align(alignof(Foo), 10 * sizeof(Foo), space, len));
assert(space != nullptr);
// construct objects in &space[i]
Qualify the definition of space
with alignas
alignas(Foo) char space[10 * sizeof(Foo)];
Make space
an array of a suitable specialization of std::aligned_storage
(thanks to @RMF)
std::aligned_storage<sizeof(Foo), alignof(Foo)>::type space[10];
Foo *p = new (&space[3]) Foo('x', true, Blue);
Foo *q = new (&space[6]) Foo('x', true, Blue);
The easiest way is by far to use std::vector
:
std::vector<Foo> foo;
You can call foo.reserve(10)
to allocate the memory, if needed. And if you have C++11, you can use foo.emplace_back(/*args*/)
to create the objects directly into the array, no need to copy.
If you don't want to/ can't use std::vector
, you can do it manually:
unsigned char foo[10 * sizeof(Foo)];
And then to construct the objects use the placement new:
int x = ...;
Foo *fooX = new (foo[x * sizeof(Foo)) Foo(/*args to the constructor*/);
But then you will have to call the destructors manually, eventually:
fooX->~Foo();
But note that this solution may have difficulties with the alignment of the byte array. You may prefer to use malloc()
to be sure:
unsigned char *foo = malloc(10 * sizeof(Foo));
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With