3

Given a class Foo which has some value-initializing default constructor:

class Foo {
private:
    uint32_t x;

public:
    constexpr Foo()
        : x { 3 }
    {}
    // ... and some other constructors
};

I need to allocate an array of these Foo's. I don't want the array's elements' default constructors to run, because later I'm going to initialize each element explicitly anyway. Something like this:

Foo foos[20000];

for (int i = 0; i < 20000; ++i) {
    foos[i] = init(i);
}

Is there a way to obtain such an uninitialized array of Foo's given that we're not allowed to change the default constructor of Foo into a non-initializing one?

By the way, this is how you'd create an uninitialized array in D:

Foo[20000] foos = void;

...and here's the same in Rust:

let mut foos: [Foo; 20000] = unsafe { std::mem::uninitialized() };
18
  • 1
    @zch: Beware of alignment. Commented Mar 12, 2015 at 1:45
  • 1
    @zch that violates strict aliasing, unfortunately Commented Mar 12, 2015 at 1:51
  • 1
    Actually, cppreference has an example that deals with similar problem en.cppreference.com/w/cpp/types/aligned_storage Commented Mar 12, 2015 at 1:51
  • 1
    @zch char may be used to alias other types, but other type may not be used to alias char Commented Mar 12, 2015 at 1:54
  • 1
    @MattMcNabb: std::array doesn't have constructors. Commented Mar 12, 2015 at 2:26

3 Answers 3

2

If you using C++11, you can use std::vector and emplace_back()

vector<Foo> foos;
for(int i = 0; i < 20000; ++i)
    foos.emplace_back( /* arguments here */);
Sign up to request clarification or add additional context in comments.

10 Comments

This works but if the purpose of using a C-style array and avoiding the use of default constructors was performance (why else?) using a vector may be slower.
@NeilKirk profile before assuming... The vector could initially reserve(20000); to avoid unnecessary allocations. Anyway I don't see a better option than this.
@MattMcNabb I agree with you, however given the context of the question, I assumed he was looking for micro-optimizations given some profiling already. Also is a compiler allowed to do that by the standard?
What if I'd like to allocate the array on stack instead of heap. Is it possible to do the same kind of magic that std::vector does under the hood (with reserve and emplace_back) with a stack-allocated blob of uninitialized memory?
@NeilKirk: I don't have any specific issue at hand. My goal is to learn to do this just in case I ever encounter a performance issue which could be alleviated by not initializing each element twice.
|
2

Perhaps this answers the question at hand more accurately?

#include <type_traits>

class Foo {
private:
    uint32_t x;

public:
    constexpr Foo()
        : x { 3 }
    {}

    constexpr Foo(uint32_t n)
        : x { n * n }
    {}
};

    // ...and then in some function:

    typename std::aligned_storage<sizeof(Foo), alignof(Foo)>::type foos[20000];

    for (int i = 0; i < 20000; ++i) {
        new (foos + i) Foo(i);
    }

The drawback seems to be that you can use only a constructor to initialize those elements, and not a free function or anything else.

Question: Can I then access those Foo's like this:

    Foo* ptr = reinterpret_cast<Foo*>(foos);
    ptr[50] = Foo();

1 Comment

Objects can only be constructed via their constructor, it's not a "drawback" so much as "working as intended". Your access code seems correct, so long as you do it after the construction loop of course.
1

What you might be looking for is std::get_temporary_buffer:

int main()
{
  size_t n = 20000;
  auto buf = std::get_temporary_buffer<Foo>(n);
  if (buf.second<n) {
    std::cerr << "Couldn't allocate enough memory\n";
    return EXIT_FAILURE;
  }

  // ...

  std::raw_storage_iterator<Foo*,Foo> iter(buf.first);
  for (int i = 0; i < n; ++i) {
    *iter++ = Foo();
  }

  // ...

  std::return_temporary_buffer(buf.first);
}

2 Comments

It's implementation-defined just how efficient those temporary buffers are. I checked on one of the Visual Studios and it just secretly called new.
Interesting, but deprecated in C++17 and removed in C++20.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.