为什么在使用迭代器时添加到向量不起作用?

时间:2014-03-19 13:16:33

标签: c++ c++11 vector iterator c++-standard-library

我有两个代码示例,它们完全相同。一个是C ++ 03和C ++ 11。

C ++ 11

int main()
{
    vector<int> v = {1,2,3};

    int count = 0;

    for each (auto it in v)
    {
        cout << it<<endl;

        if (count == 0)
        {
            count++;
            v.push_back(4);//adding value to vector
        }
    }

    return 0;
}

C ++ 03

int main()
{
    vector<int> v = {1,2,3};

    int count = 0;

    for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
    {

        cout << *it<<endl;

        if (count == 0)
        {
            count++;
            v.push_back(4);//adding value to vector
        }
    }

    return 0;
}

这两个代码都给出了以下异常。

enter image description here

现在,当我看到vector :: end()实现时,

iterator end() _NOEXCEPT
{   
// return iterator for end of mutable sequence
return (iterator(this->_Mylast, this));
}

这里,内联函数显然需要_Mylast来计算结束。因此,当我添加时,它的指针将递增到下一个位置,如_Mylast++。为什么我得到这个例外?

感谢。

2 个答案:

答案 0 :(得分:10)

向量将其元素存储在连续的内存中。如果需要重新分配该内存块,则迭代器将变为无效。

如果您需要在迭代时修改向量的大小,请按索引而不是iterator进行迭代。

另一种选择是使用具有不同迭代器行为的不同容器,例如list将允许您在插入项目时继续迭代。

最后,(我敢建议吗?)如果你知道你的向量将增长到的最大大小,.reserve()之前迭代它。这将确保它在循环期间不会重新分配。我不确定这种行为是否由标准保证(也许有人可以插入);我绝对不会这样做,考虑通过索引迭代是完全安全的。

答案 1 :(得分:4)

您的push_back使您在for循环中使用的迭代器无效,因为该向量正在重新分配其内存,这会使所有迭代器无效到向量的元素。

惯用解决方案是使用insert_iterator,就像在向量上调用std::back_insterter时得到的那样。然后你可以这样做:

#include <iostream>
#include <iterator>
#include <vector>

int main()
{
  std::vector<int> v;
  auto inserter = std::back_inserter(v);
  for(int i=0; i<100; ++i)
    inserter = i;

  for(const auto item : v)
    std::cout << item << '\n';
}

即使通过底层容器的重新分配调用,它也能确保自己的有效性。

Live demo here