为什么向量的最后一个元素的迭代器持有损坏的值? (参考代码)

时间:2019-03-25 06:34:40

标签: c++11 iterator stdvector stdlist

下面的代码引发“堆后释放后使用”错误。

#include <iostream>

int main()
{
    unordered_map<int, vector<int>::iterator> mp;
    vector<int> num;

    auto insert = [&](int n)
    {
        if (mp.count(n) != 0)
            return false;

        num.push_back(n);
        mp[n] = prev(num.end());
        return true;    
    };

    insert(1);
    insert(2);
    insert(3);

    for (auto n : num)
        cout << n << endl;

    cout << endl;

    for (auto m : mp)
    {
        cout << m.first << " -> ";
        cout << distance(num.begin(), m.second) << endl; 
        // cout << *m.second << endl;
    }

    return 0;
}

以上代码的输出为

1
2
3

3 -> 2
1 -> -16
2 -> -7

如果我尝试访问*m.second,显然会崩溃。 为什么这里的迭代器值似乎被破坏了?

我尝试用list替换vector,并且上面的代码工作正常。我想知道这是否与向量如何在“ push_back”上扩展有关。我尝试了其他方法来使迭代器到达向量的最后一个元素,且结果无关紧要。

1 个答案:

答案 0 :(得分:0)

调用vector时,迭代器和引用在push_back中无效,请参见reference。向量被实现为一个连续的存储块。当您推送新元素并且没有空间保留它们时,将分配新的内存块并添加新的elem。因此,旧元素的迭代器(指针)可能无效。

您的代码可在std::list上使用,因为列表是使用 nodes 实现的。一个节点指向另一个节点,并且在将新数据添加到节点的列表位置时不会更改,因此迭代器有效。

您的带有vector的代码可以使用,但是您需要估算向量中可以包含多少个元素,在创建向量后调用reserve(N)-它准备将向量保存{{1 }}项,而在调用N时不会使迭代器无效。