0

When I fill an std::vector knowing in advance the final size, I usually reserve its capacity in advance to avoid reallocation of its content (which on C++03 involves calling copy constructors for each object already stored in the vector).

This is a trivial example:

std::vector<std::string> v;
v.reserve(10);    

for( std::vector<std::string>::size_type i = 0, capacity = v.capacity();
     i < capacity;
     ++i )
{
    v.push_back(std::to_string(i));
}

There's a better way (less C-style) to loop around the std::vector capacity?

I'm looking for both C++03 and C++11 answers.

Edit: I rewrote the sample because all the answers and comments were going off topic, concerning only filling the std::vector with an array, which is not the point of the question.

lornova
  • 6,667
  • 9
  • 47
  • 74
  • A better as opposed to what? What is the problem with the current `fill` you want to avoid? – SergeyA Dec 31 '15 at 18:29
  • May be you just want to convert an array into a vector ? http://stackoverflow.com/questions/8777603/what-is-the-simplest-way-to-convert-array-to-vector – mikedu95 Dec 31 '15 at 18:30
  • 8
    It would work with just `std::vector v(t, t + size);`. – Bo Persson Dec 31 '15 at 18:30
  • @SergeyA: better in the sense "more C++ style"... this is very much C style. – lornova Dec 31 '15 at 18:32
  • @mikedu95: this is just an example, I'm looking for a generic answer on how to loop around an std::vector capacity – lornova Dec 31 '15 at 18:34
  • 2
    @Lorenzo, what is 'loop around capacity'??? – SergeyA Dec 31 '15 at 18:42
  • Please do not mix size and capacity. Notice: vector::size() <= vector::capacity() (capacity is a size threshold for reallocation) –  Dec 31 '15 at 18:42
  • @SergeyA: it means looping not for the size() but for the capacity(). For the size you have the iterators, for the capacity you don't. – lornova Dec 31 '15 at 19:58
  • I suppose `while (v.size() < v.capacity()) { ... }` is not what you are looking for. But I don't know what else could be the answer since using a reference to a as-yet-unconstructed element of the vector is UB even if space has been reserved. – rici Dec 31 '15 at 23:04
  • @rici: I'm looking for something more object oriented... like iterators or range-based for()... these methods work with allocated items of the std::vector, but I have not been able to find something for reserved items. – lornova Dec 31 '15 at 23:07
  • ...Of course, you could assign through a `std::vector::back_insert_iterator` instead of using `std::vector::emplace_back`. I really don't see the advantage, though, and the back_insert_iterator cannot be compared with a std::vector::iterator, so it's not going to be much use for loop control. But, fwiw, it's an iterator :) – rici Dec 31 '15 at 23:23
  • What *is* the point of the question? What do you actually want to achieve? – Richard Hodges Jan 01 '16 at 01:08
  • 1
    @Lorenzo: Note that after your `std::vector::reserve(n)`, capacity may be greater than `n`, so you fill your vector for a size which is implementation specific... – Jarod42 Jan 01 '16 at 04:45

2 Answers2

6

You don't really need a loop at all. There is an overload of std::vector constructor that takes two iterators. So just use std::begin and std::next to get the start and end of the passed-in array and make a vector from that.

template<typename T>
std::vector<T> fill(const T* t, size_t size)
{
    return {std::begin(t), std::next(std::begin(t), size)};
}

Similarly you could use pointer arithmetic, which is what the above method essentially does under the hood:

template<typename T>
std::vector<T> fill(const T* t, size_t size)
{
    return {t, t + size};
}
lornova
  • 6,667
  • 9
  • 47
  • 74
Cory Kramer
  • 114,268
  • 16
  • 167
  • 218
  • There is still a loop under the hood, and since the question starts with 'reserve', I have the feeling OP is talking about performance?... Not sure still. – SergeyA Dec 31 '15 at 18:36
  • 2
    @Sergey - If the vector constructor does any worse than using a reserve, you should ask for you money back from the library developer. – Bo Persson Dec 31 '15 at 18:44
  • @BoPersson, would be hard given I got it for free :) But this is not what I meant. I was trying to say that my first impression was that OP is trying find a more performant solution, than reserve + loop. Possibly I am wrong. I am still not sure what they want. – SergeyA Dec 31 '15 at 18:47
  • @CoryKramer: thanks for the answer but it is off topic... I'm not looking at a way to fill a vector with an array (that was just an example, now I changed the code to better reflect my question), the question is about iterating the `capacity()` of an `std::vector`. – lornova Dec 31 '15 at 20:15
0

In c++11 or better, if you fill a vector knowing its size std::initializer_list will be your best bet.

You probably want to avoid initialising through a pointer to an array of const objects because that almost guarantees a copy. I appreciate that this is necessary in c++03, which should be one of your main motivations to move to a newer compiler if possible.

so:

std::vector<Thing> mythings { Thing(1), Thing(2), Thing(3) };

Is about as fast as you can get it. (not that there is no need for a fill function).

If you compile this on a reasonably modern compiler with optimisations on, you'll find that the Things will actually be created in-place within the vector. There is no faster way.

Richard Hodges
  • 68,278
  • 7
  • 90
  • 142