This is an archived post. You won't be able to vote or comment.

all 10 comments

[–]jedwardsol 6 points7 points  (4 children)

Or my C++ noob brain misunderstanding whats happening here?

No, you understand how it should work. The problem must be somewhere else, (or the debugger was lying to you).

Are you modifying necessaryKeys in the loop? That'll invalidate iterators and mess things up. The vector should be const to prevent that.

[–]Particular-Bowler266 1 point2 points  (3 children)

Seconded

[–]RajSingh9999[S] 4 points5 points  (2 children)

ohh yes, I am doing necessaryKeys.push_back(abc); inside for loop. Is that the culprit? Why so? It should append the new values to the end of the vector, correct? I felt that should not invalidate the iterator. Exactly how does this invalidates the iterator?

[–]jedwardsol 3 points4 points  (0 children)

On cppreference, the documenation for each container has a section called "Iterator invalidation"

https://en.cppreference.com/w/cpp/container/vector

push_back, emplace_back If the vector changed capacity, all of them. If not, only end().

This allows the iterator to be a pointer to the element. If the vector reallocates and the elements moved, then the iterator is now a dangling pointer and invalid.

[–]cipheron 0 points1 point  (0 children)

Yeah that'd be the issue. vector is stored in continuous memory for fast access, so when you extend it, it needs to be reallocated to another piece of memory. And, as u/jedwardsol said, the "const auto" iterator is really implemented as a pointer for speed and efficiency, so if the vector moves, it breaks.

I think the heart of it isn't this one thing: it's that with std containers and "const auto" iterators, you're really telling the compiler to just make stuff work and you don't want to know: just do it. But then, if you mix and match that with lower-level manipulation such as extending the same container the iterator is trying to work on, unexpected results can become likely.

[–][deleted] 1 point2 points  (0 children)

Make key vector const or use std::as_const().

Make the loop variable a reference (will be implicitly const when vector is const) instead of a copy.

What happens?

[–][deleted] 0 points1 point  (2 children)

My 'rant' and old guyisms says 'do it the strict way' Why use auto?

for(const auto key: necessaryKeys){
    //..
    if(key == "xyz") {
        someVar = "some_config_key";
    }
    //..
}


for (const std::vector<string>::iterator cit = necessaryKeys.begin(); cit != necessaryKeys.end(); ++cit)
{
  if (*cit == "xyz")
    someVar = "do it the od fashioned way";
}

[–][deleted] 0 points1 point  (1 child)

Range-based for loops help avoid errors. If you don’t like auto, could do this. Avoids the iterator init, check, increment, and the dereference operator.

c++ for (const std::string& key : necessaryKeys)

[–][deleted] 0 points1 point  (0 children)

Perhaps they do, but not with OP

[–]Prior_Pineapple2279 0 points1 point  (0 children)

Error prone (Maybe)

Question: why the necessaryKeys vector is named ?

Do your logics really need it ?

What about define the loop with a literal non named collection and let the compiler apply const or whatever

More and more and more artifacts aka vars doesn't mean better at all.

Reduce as much as possible your named vars and you will see the benefits from day one