C++: push_back in std::vector while iterating it

北战南征 提交于 2020-06-14 05:50:34

问题


Following code snippet provides a very weird output. I was expecting an overflow( Python gives a MemoryError)

#include <iostream>
#include <vector>

int main()
{
    std::vector<int> a{1,2,3};

    for( auto const & item : a)
        a.push_back(item);


    for( auto const & item : a)
        std::cout<<item<<',';

    return 0;
}

Output: 1,2,3,1,0,3,

How do I interpret this result?

If you do a similar thing in Python, it gives a memory error.

>>> a = range(0,20)
>>> for i in a:
    a.append(i)



Traceback (most recent call last):
  File "<pyshell#3>", line 2, in <module>
    a.append(i)
MemoryError

>>> 

This question came to my mind, because above way of writing code is considered to be bound-safe. And for bound safety container should not grow/shrink during foreach type iteration. So, this is a leaky abstraction.

Is there a way one can wrap this foreach loop so that any operation causing size-modification/reallocation is not allowed in the loop body.


回答1:


In C++ adding elements to a vector may cause reallocation of the contained data, which will invalidate all iterators. That means you can't loop over the vector using iterators (which is what the range-based for loop does) while also inserting new elements.

You can however iterate using indexes and use the vector size as condition, since indexes will always be the same.




回答2:


If the vector is resized, the iterator will become invalid.

You could do it if you reserve in advance.

Keep in mind that for range will operate on the iterator bounds defined before any changes are made. So will only get a copy of your list appended.

#include <iostream>
#include <vector>

int main()
{
    std::vector<int> a{1,2,3};

    a.reserve(10);           // 10 should be enough to get a copy without reallocating
    for( auto const & item : a)
        a.push_back(item);

    for( auto const & item : a)
        std::cout<<item<<',';

    return 0;
}

Output:

1,2,3,1,2,3,

I would not recommend an approach like this because I don't consider it clean or clear. However, if you refer to the standard, this behaviour is expected:

23.3.6.5 vector modifiers

With respect to the use of insert,emplace,emplace_back, push_back.

Remarks: Causes reallocation if the new size is greater than the old capacity. If no reallocation happens, all the iterators and references before the insertion point remain valid.

That is, if no reallocation happens, you can trust your iterators before the insertion point. So as long as the capacity of your vector is high enough, you can append with no problems.



来源:https://stackoverflow.com/questions/35938329/c-push-back-in-stdvector-while-iterating-it

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!