"Automatic" fill

Started by
22 comments, last by alvaro 13 years, 4 months ago
Hi,
Im testing the fill <algorithm> command.
I want to fill a vector of five elements with numbers 1 - 5.
I think a for loop could do this. But there is a problem:

vector<int> vec(5);
for(int f = 1; f < 5; ++f)
{
fill( vec.begin()+(--f), vec.end(), f );
}

As you can see I want to start at position 0, and with the val 1. Then it should
automatically assign each value every iteration.
Logically I think it would work, but instead it becomes an endless loop.
I know I could do one more value and it would work, but do you see any thinner solution or answer? Thanks!


Advertisement
Think logically about what the '--f' is doing in that loop and you'll soon realise why it becomes an infinite loop.

I'm pretty sure you have a nice chunk of undefined behaviour there as well with the args to the 'fill' function; if memory serves the order parameters are evaluated aren't fixed, and I'm pretty sure the access/modification to 'f' is undefined as well (lack of sequence points).
(Someone correct me if I'm wrong here).
Why are you trying to use std::fill() here? Using std::fill() to set the value for a single element seems rather silly.
When you fix that, be sure to change your loop condition either to f<=5 or f < 6. Otherwise you'll only get the numbers 1 -> 4.
vector<int> vec(5);int f = 1;for(auto it = vec.begin(); it != vec.end(); ++it){    *it = f++;}

Quote:Original post by Chris_F
vector<int> vec(5);int f = 1;for(auto it = vec.begin(); it != vec.end(); ++it){    *it = f++;}


You can simplify it even more if you're going to use C++0x, by using initializer lists (assuming compiler support is there currently):

std::vector<int> vec = {1, 2, 3, 4, 5};
From your answers I think I now know why it doesn't work, the for-loop is
a statement in which a formal parameter always increment it's own scope no matter if you try to use it just for positioning instructions only:

fill(vec.begin() + 0, vec.end(), 1)
->
fill(vec.begin() + 4, vec.end(), 5)
---------------------------------- =
fill(vec.begin() +(--f), vec.end(), f)

Besides your examples, this also works well :
fill(vec.begin()+f, vec.end(), f + 1)

But is it someway possible to make use of "icrementing / decrementing instructions" in iterative loops at all?
I didn't understand what the OP problem is, sorry.

I just wanted to point out that this statement is undefined behavior:
fill( vec.begin()+(--f), vec.end(), f );


You are modifying f and using it in another part of the expression, without a sequence point in between.

Basically you are just trying to use an algorithm for something that it is not supposed for. Why use a O(n*n) algorithm for a O(n) operation?

There are many better ways, e.g using a counting_iterator from boost.

#include <vector>#include <boost/iterator/counting_iterator.hpp>#include <iostream>#include <algorithm>#include <iterator>int main(){    std::vector<int> vec(5);    std::copy(boost::make_counting_iterator(1), boost::make_counting_iterator(6), vec.begin());    std::copy(vec.begin(), vec.end(), std::ostream_iterator<int>(std::cout, " "));    std::cout << '\n';}
The purpose of std::fill is to assign the same value to many elements of a sequence.

What you are trying to do is assign a different value to each of several elements, following some rule. The natural choice of standard library algorithm for this is std::generate.

The example of std::generate given in this doc even solves your specific problem.

You can also use a "counting iterator" (via third-party tools, or rolling it yourself) as shown in visitor's code. The idea is that we have objects that obey the iterator interface while pretending to "iterate" over a virtual, not-actually-existing "container" of all the integers in order; then we use the standard library algorithm std::copy to copy from this virtual container into a real one in order to get a sequence of real elements.

The infinite loop in your code is caused by the fact that '--f' changes the value of f in addition to simply producing the value used in your calculation. This cancels out the '++f' in the for-loop clause, so each time through the loop, 'f' has the same value, and the loop-exit condition is never met.

EDIT: Except for the part where, as alvaro correctly points out, this actually invokes undefined behaviour, although all practical compilers would produce something that ends up in an infinite loop (it's just that the actual effects on the container might vary).

This topic is closed to new replies.

Advertisement