user39275 user39275 - 1 month ago 19
C++ Question

Populate vector with integer sequence, on construction

I am trying to populate a

vector
(or other container) with a sequence of integers on construction of the vector (contrasting to this question). The following code does what I intend, using the range constructor for a
vector
, and Boost's counting_range:

#include <iostream>
#include <vector>
#include <boost/range/counting_range.hpp>

using namespace std;

int main () {
vector<int> test_vector(boost::counting_range(2,10).begin(),boost::counting_range(2,10).end());
for (auto i : test_vector) cout << i << endl;
}


Questions:

  1. Can I eliminate the duplication in
    counting_range(2,10).begin()
    and
    counting_range(2,10).end()
    ? Currently I'm specifying the range of (2,10) twice.
  2. Can this be done without Boost, using just vanilla C++11 or C++0x? Edit: or C++14?


Edit:


  • I'd like to instantiate the vector and specify the range all in a single statement. For example in Python I could write
    test_vector=range(2,9)
    . In R/Octave/Matlab one can write
    test_vector=2:9
    or
    test_vector=seq(2,9,1)
    . In this regard I'm satisfied with what I have above.
  • I used "2" and "10" above, but boundary of the range could be dynamic, any integers a,b in scope with a≤b. So an initialization list like {2,3,...,9} isn't desirable since it must be specified at compile-time.
  • The method I've used above can also be used to initialize other containers in a single statement; the following also works:
    unordered_set test_set(boost::counting_range(2,10).begin(),boost::counting_range(2,10).end());

    It would be nice if any solution was also as 'container independent'.
  • I agree with @david-rodriguez-dribeas that we can adhere to Meyer's Item by initializing the vector in the constructor's body; it isn't necessary for it to be done in the constructor's initialization list. So I have struck-out this portion below.



Motivation:
I want to do this is because I want to obey Meyer's Item 4 ("Make sure objects are initialized before they are used.") in Effective C++ elsewhere in my code. For example:

class my_class {
public:
my_class()
:vec(boost::counting_range(2,10).begin(),boost::counting_range(2,10).end()) {}
vector<int> vec;
};



Answer

Don't over do it. The simple thing to do is to default initialize the vector, reserve and initialize from the range.

Make sure objects are initialized before they are used.

That does not mean that the member must be fully initialized in the initialization list, rather than the my_class object must be fully initialized when the constructor completes.

Other than that, just for the sake of it, there are different things you can do in vanilla C++ to handle this, like creating a helper function and returning the vector by value:

std::vector<int> create_vector() {
   std::vector<int> v;
   // ...
   return v;
}

But I would not use this (or any other alternative) to initialize a member, only if needed (the vector is const might be sufficient excuse :))