3

Firstly, I'd like to apologise if this is a blinding simple and obvious question. I know it's a fairly easy one to people with the know-how. C++11 allows vectors to be initialised in list form:

std::vector<std::string> v = {
    "this is a",
    "list of strings",
    "which are going",
    "to be stored",
    "in a vector"};

But this isn't available in older versions. I've been trying to think of the best way to populate a vector of strings and so far the only thing I can really come up with is:

std::string s1("this is a");
std::string s2("list of strings");
std::string s3("which are going");
std::string s4("to be stored");
std::string s5("in a vector");

std::vector<std::string> v;
v.push_back(s1);
v.push_back(s2);
v.push_back(s3);
v.push_back(s4);
v.push_back(s5);

It works, but it's a bit of a chore to write and I'm convinced there's a better way.

BЈовић
  • 62,405
  • 41
  • 173
  • 273
Mike8580
  • 45
  • 5
  • 3
    Use an array to initialize it. You should be able to find examples on tutorials to `std::vector`. – chris Sep 30 '13 at 22:17
  • Check out this related question: http://stackoverflow.com/questions/231491/how-to-initialize-const-stdvectort-like-a-c-array/231495#231495 – Ferruccio Sep 30 '13 at 22:21

3 Answers3

6

The canonical way is to define begin() and end() functions in a suitable header and use something like this:

char const* array[] = {
    "this is a",
    "list of strings",
    "which are going",
    "to be stored",
    "in a vector"
};
std::vector<std::string> vec(begin(array), end(array));

The functions begin() and end() are defined like this:

template <typename T, int Size>
T* begin(T (&array)[Size]) {
    return array;
}
template <typename T, int Size>
T* end(T (&array)[Size]) {
    return array + Size;
}
Dietmar Kühl
  • 150,225
  • 13
  • 225
  • 380
  • 1
    @NemanjaBoric: of course, I'm using `begin()` and `end()`! As far as I know I was the first who described this technique publicly at some point in the [last millennium](https://groups.google.com/forum/#!topic/comp.lang.c++.moderated/0Pr5ecSTwZw). These function templates were also one of first [Boost contributions](http://hepunx.rl.ac.uk/BFROOT/dist/packages/boost/V01-27-00-04/libs/array_traits/array_traits.html). – Dietmar Kühl Sep 30 '13 at 22:51
  • Just for the benefit of people like me, who weren't aware of this, this capability now appears to be in the [Boost.Range library](http://www.boost.org/doc/libs/1_54_0/libs/range/doc/html/index.html). – Fred Larson Sep 30 '13 at 23:30
  • The advantage of this solution is that it is perfectly forward-compatible with C++11. It is even possible to wrap this in macros so that it [looks as if initializing](http://ryan.gulix.cl/fossil.cgi/cxxomfort/wiki?name=Features/Extras#cxxo-i12n) a C-array (and that can be made C++11-compatible as well): `SOME_WRAPPER(vector vec) = {"this is a", "list of strings", ...., };` – Luis Machuca Oct 01 '13 at 05:25
  • Yes, it's also [in the iterator library](http://en.cppreference.com/w/cpp/iterator/begin) in C++11. – Fred Larson Oct 01 '13 at 17:44
4

As chris noted, you could store all literals into the array, and then initialize vector from that array:

#include <vector>
#include <iostream>
#include <string>

int main()
{
        const char* data[] = {"Item1", "Item2", "Item3"};
        std::vector<std::string> vec(data, data + sizeof(data)/sizeof(const char*));
}

You don't need explicit conversion to std::string.

Nemanja Boric
  • 21,627
  • 6
  • 67
  • 91
1

If you're "stuck" with pre-C++11 C++, there are only a couple of alternatives and they're not necessarily "better".

First, you can create an array of constant C strings and copy them into the vector. You might save a little typing, but then you have a copy loop in there.

Second, if you can use boost, you could use boost::assign's list_of as described in this answer.

Community
  • 1
  • 1
Timo Geusch
  • 24,095
  • 5
  • 52
  • 70