How can you reserve space for an array without initializing each element?

The following code will create an array of 10 Foo objects with the default Foo constructor:

Foo foo[10];

but I don’t want to do this, I have a havy foo constructor, and later I will regenerate all the foo objects one by one and assign (copy) it to the elements of the foo array, so it makes no sense to initialize the array, I just want to reserve a place for it and install it later. As with

int foo[10]

when foo elements will not be initialized without = {}. How can I do this without using the std namespace (I will use the code on both PC and CUDA, which does not support std)?

+4
source share
6

, : .

// allocate memory
char * space[10 * sizeof(Foo)];

// make sure it 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();

- , . ; :

  • std::align ( @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]
    
  • space alignas

    alignas(Foo) char space[10 * sizeof(Foo)];
    
  • space std::aligned_storage ( @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);
    
+12

- std::vector:

std::vector<Foo> foo;

foo.reserve(10), , . ++ 11, foo.emplace_back(/*args*/) , .

/ std::vector, :

unsigned char foo[10 * sizeof(Foo)];

:

int x = ...;
Foo *fooX = new (foo[x * sizeof(Foo)) Foo(/*args to the constructor*/);

, :

fooX->~Foo();

, . malloc(), :

unsigned char *foo = malloc(10 * sizeof(Foo));
+5

- std::vector

std::vector<Foo> foovec;
foovec.reserve(10);

, 10 Foo, .

, - , placing-new

char* place = static_cast<char*>(::operator new(sizeof(Foo) * 10));

-new.

Foo* f1 = new (place) Foo(...);
Foo* f2 = new (place + sizeof(Foo)) Foo(...);
//
f1->~Foo();
f2->~Foo();
::operator delete(place);
+2

, std::vector reserve push_back.

... , .. , , . boost::optional , std::vector<boost::optional<Foo>> .

+2

( OP ):

  • STL;
  • ( ).

, , , , OP ++ 11, ++ 11.

Foo, :

union FooStorage {

    Foo data;

    FooStorage() {
    }

    template <typename... Args>
    void init(Args&&... args) {
        new (&data) Foo{static_cast<Args&&>(args)...};
    }

    ~FooStorage() {
        data.~Foo();
    }
};

, data, . data ( init()) . ( OP , , .)

, { ... } ( ... ) . Foo.

10 Foo

FooStorage buffer[10];

i -th Foo:

buffer[i].init(/* constructor arguments */);

To use i-th Foo, for example, by calling its method do_something:

buffer[i].data.do_something();

This is the main idea. There are many improvements that can be made with FooStorage.

0
source

Array boost::optional<Foo>or C ++ 14std::optional<Foo>

boost::optional<Foo> foo[10];

?

0
source

All Articles