Home > database >  Initializing some elements of vector of defined size
Initializing some elements of vector of defined size

Time:06-11

Is there a way to initialize first few elements of a vector after defining the size of the vector like -

vector<int> vec (10);

This doesn't work and produces a compiler error -

vector<int> vec(10) {1,2,3};

For example with arrays we can do the same thing like -

int arr[5] {1,2,3}; // This will initialize the first 3 elements of the array to 1,2,3 and the remaining two to 0.

CodePudding user response:

In short, no. Your can fill out the entire list of things you want to be in the vector:

vector<int> vec{1, 2, 3, 0, 0, 0, 0, 0, 0, 0};

Which will give you a vector of 10 elements.

Or, you can create the vector, then call resize to make it larger (filling the remaining elements with 0):

vector<int> vec{1, 2, 3};
vec.resize(10);

You generally don't need to do this kind of thing to vector though, because unlike array, you can extend vector as needed, after creation:

vector<int> vec{1, 2, 3};
vec.push_back(4);

CodePudding user response:

There isn't a way to do it all in one line like you can with an array. You can use

vector<int> vec{1,2,3};
vec.resize(10);

but that does make the code a little less easy to use. Another option is to wrap that in a function like

template <typename T> 
auto make_sized_vector(std::intializer_list<T> il, std::size_t size = 0)
{
    const auto vec_size = std::max(size, il.size());
    vector<T> vec;            // create vector
    vec.reserve(vec_size);    // allocate all the storage needed
    vec.assign(il);           // assign the elements
    vec.resize(vec_size);     // set the rest to zero
    return vec;
}

and then you can use that like

auto vec = make_sized_vector<int>({1, 2, 3}, 10);

If you are concerned about passing the std::intializer_list by value see why is `std::initializer_list` often passed by value? for why that really isn't a concern.

CodePudding user response:

Vector is mutable container, it stores data in the mutable heap area. Whenever you add new elements vector can reallocate heap space. As well as you can free waste heap memory with shrink_to_fit

If you don't need mutable data structure, take a look into std::array

If you just need to initialize from literal you've a few options:

Option one - use assignment from std::initializer_list

std::vector<int> v0 {0,1,2,3};

Option two - assign operator:

std::vector<int> v1 = {0,1,2,3};

Option three - back insertion of initializer_list

  std::vector<int> v2( 7 );
  v2.insert(v2.end(), {9,8,7});

For example:

#include <iostream>
#include <vector>

template<typename Iterator>
void printv(const Iterator& begin,const Iterator& end) {
  Iterator it = begin;
  std::cout << "[" << *it;
    it;
  while(it != end) {
    std::cout << ", ";
    std::cout << *it;
      it;
  }
  std::cout << "]" << std::endl;
}

int main(int argc, const char** argv) {
  
  std::vector<int> v0 {0,1,2,3,4,5,6,7,8,9};
  printv(v0.begin(), v0.end());
  
  std::vector<int> v1 = {0,1,2,3};
  printv(v1.begin(), v1.end());
  
  std::vector<int> v2( 7 );
  v2.insert(v2.end(), {9,8,7});
  printv(v2.begin(), v2.end());
  
  return 0;
}

Gives you:

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[0, 1, 2, 3]
[0, 0, 0, 0, 0, 0, 0, 9, 8, 7]

CodePudding user response:

In case you want to initialize a vector the way you describe, all at once, so that it can become (e.g.) a const member, this is always possible in C , with just a bit of ugliness and twisting. Let’s say you have a class:

struct SomeClass {
  SomeClass(const std::vector<int> &start, int rest, std::size_t size);
  const std::vector<int> some_vector_;  // This is const!
};

What the constructor could look like:

SomeClass::SomeClass(const std::vector<int> &start, int rest, std::size_t size)
    : some_vector_{[&start, rest, size] {
        std::vector<int> some_vector;
        some_vector.reserve(size);
        some_vector.insert(some_vector.end(), start.begin(), start.end());
        some_vector.insert(some_vector.end(), size - start.size(), rest);
        return some_vector;
      }()} {}

Basically the problem boils down to: How do I do “something procedural” in an initializer list? To which the answer is: You invoke a function that returns the desired type.

To test the construct above:

#include <cstdint>
#include <iostream>
#include <vector>

namespace { /* SomeClass stuff from above goes here. */ }

int main() {
  SomeClass sc{{1, 2, 3}, 0, 10};
  for (int i : sc.some_vector_) std::cout << i << '\n';
}

There are (of course) plenty of ways to make it (slightly) more efficient if needed, such as

  • a templated variadic constructor to create the initial part of the vector,
  • a templated perfect-forwarding constructor to benefit from R-value containers, and
  • as a combined benefit of the above, arbitrary iterable containers as inputs and as the const member.
  • Related