Search code examples
c++initializationstdvectordynamic-memory-allocationmemory-access

Non-Constant Generator Single-Pass Initialization during Construction


Is there a way to construct a new std::vector with uninitialized (non-zero) values or even prettier through a generator (similar to std::generate_n()) constructor argument that produces the desired non-standard (non-constant) values without first initializing all elements to zero? This because I want a (random) mockup-creation api to be as locality-efficient as possible, thereby only writing container elements once. Wouldn't it be neat to have a generator-constructor for the std::vector (and possibly others)?! Why hasn't C++ already added this to the Standard?

The following constructor-like C function illustrates the write-once-behaviour I seek for the custom-initialize construction of std::vector:

// Allocate-and-Generate a random int array of length \p n.
int * gen_rand(size_t n)
{
  int *v = malloc(n); // allocate only 
  for (size_t i=0; i<n; i++) {
    v[i] = rand(); // first write
  }
}

I believe it boils down to the behaviour of the STL Allocator used, since it is responsible for writing the initial zeros (or not).

If we use the std::vector constructor with iterators we first have to allocate and write the random values somewhere else, even worse than using push_back().


Solution

  • You can precede the use of the generator with a call to vector::reserve. This will have exactly the same behavior as the C code you show. You will still need to use a back_insert_iterator as the size of the vector will still be zero.

    #include <vector>
    #include <cstdlib>
    #include <algorithm>
    #include <iterator>
    #include <iostream>
    
    
    int main()
    {
      std::vector<int> v;
      v.reserve(10);
      std::generate_n(std::back_inserter(v), 10, []() { return rand(); });
      for(auto x : v)
        std::cout << x << std::endl;
      // unsafe version
      std::vector<int> v2;
      // 10 uninitialized integers
      v2.resize(10);
      // make sure never to write more than the exact amount, otherwise this will be UB
      std::generate_n(v.begin(), 10, []() { return rand(); });
    
      return 0;
    }