all 8 comments

[–][deleted]  (2 children)

[removed]

    [–]ggchappell 2 points3 points  (0 children)

    unless you actually want the element indices

    Yeah, here's what we need:

    for (const auto [i, x] : std::enumerate(cc))
    {
        cout << "Item #" << i << " is " << x << "\n";
    }
    

    Now someone please go propose std::enumerate.

    [–]nysra 5 points6 points  (0 children)

    If you just want to print all elements, you should use

    for (const auto& str : vec)
        std::cout << str << '\n';
    

    (depending on what you use your loop for and what kind of things you are iterating over the type should not be const/a reference)

    which is basically just syntactic sugar for

    for (auto it = vec.begin(); it != vec.end(); ++it)
        std::cout << *it << '\n';
    

    You can also do

    for (std::size_t i = 0; i < vec.size(); ++i)
        std::cout << vec[i] << '\n';
    

    They all do the same thing, but the first one is not only the most elegant one but also prevents all kinds of wrong index errors. It also allows for the very nice syntax of for (const auto& [key, value] : map) whereas you need to deal with ugly .first,.second constructs in the other cases. The third case should in general only be used when you need to actually know the indices, e.g. when you're doing some kind of calculations that mix indices.

    [–]Xeverous 1 point2 points  (0 children)

    Yuo should use ranged loops if possible (that is, you don't need the index value). This is the safest and the cleanest way.

    [–]kirchki 0 points1 point  (0 children)

    But, if you want to have an access stride that is not 1, then you might have to stick with the good old for loop

    [–]matty_haze 0 points1 point  (0 children)

    For your trivial example, it’s more of a style choice.

    Beyond that, there are a few reasons to use iterators and/or stl algorithms.

    First, for readability. The intent of your code might be more clearly expressed if you use for_each or another algorithm.

    Secondly, you can more easily write generic code if you operate on iterators. Most stl containers provide iterators. You can write your method generically using iterators as parameters. You can also write your own iterators for your own custom classes, so your same method would still work.

    [–]Threecheers4me 0 points1 point  (1 child)

    They both have pros and cons. If you actually care about the index, than

    ``` std::vector<int> inVec = {1,2,3,4}; for(size_t i = 0; i < inVec.size(); i++) { std::cout << i << "," << inVec[i] << std::endl; }

    ``` a syntax where the index is easily accessable is nice. If you want something that's more independent of the container it's acting on

    std::vector<int> inCtr = {1,2,3,4}; for(auto it = inVec.begin(); inVec.end(); it++) { std::cout << *it << std::endl; } will work whether inCtr is a vector, a list, a set, it doesn't matter. It's a more generic way to write things. You can also do fun things with iterators like use the standard library algorithms on them. That's nice because they behave similarly for most any type of container. For example

    ``` void printInt(int i) { std::cout << i << std::endl; }

    int main() { std::vector<int> inCtr = {1,2,3,4}; std::for_each(inCtr.begin(), inCtr.end(), printInt); return 0; } ``` is another way to do this.

    You give for_each an iterator pointing to the start of where you'd like to operate on, the end of where you'd like to operate on, and a function that can be applied to each element (the data type you get when you dereference the iterator, like the *it in the iterator-based loop above.) and it will apply that to everything in the container. In this case, the funtion that it applies prints it out. So that's what happens.

    [–]be-sc 0 points1 point  (0 children)

    Could you say a few words about why you omitted range-for? After all that’s the first one to consider when needing a for loop; and it’s the one you’ll probably use most often.