我在使用带有 vector STL 的迭代器时遇到了这个错误。
代码:-
#include <iostream>
#include <vector>
void print_vec(std::vector<int> vec)
{
auto itr = vec.begin();
while (itr != vec.end())
std::cout << *itr++ << " ";
std::cout << std::endl;
}
int main(int argc, char* argv[])
{
std::vector<int> vals = { 1, 2, 3, 4, 5, 6 };
print_vec(vals);
auto it = vals.begin();
vals.insert(it, 100);
print_vec(vals);
it += 4;
std::cout << *it << "\n";
vals.insert(it, 200);
print_vec(vals);
return 0;
}
输出:-
1 2 3 4 5 6
100 1 2 3 4 5 6
5
0 100 1 2 3 4 5 6
double free or corruption (out)
Aborted (core dumped)
我不明白为什么会发生这种情况:修改 vector 后迭代器是否存在问题?我认为我对迭代器的直觉是有缺陷的。
最佳答案
当一个 std::vector
调整大小时,迭代器变得无效,因为它在调整大小之前引用了 vector ,这可能包括将 vector 移动到不同的内存位置以保持连续性。在那种情况下 it
不会自动更新以引用新位置。
这种情况下的结果(因为它是未定义的行为)是值 200
没有插入 vector 中,但它被写入了 vector 先前占用的其他一些堆内存,该 vector 已被释放 - 即您损坏了堆。 vector 在从 main 退出时被销毁,此时系统堆管理失败并报告错误(事后)。
在插入之后重新分配迭代器可以解决问题:
it = vals.insert(it,100);
...
正如您所期望的那样,单个项目的输出报告 5 而不是 4,因为它只是读取尚未重用的旧 vector 内存并被其他内容覆盖。
您可以通过比较观察错误:
vals.insert(it,100);
std::cout<<std::distance(it,vals.begin())<<'\n' ;
和
it = vals.insert(it,100);
std::cout<<std::distance(it,vals.begin())<<'\n' ;
您的结果可能会有所不同,但在 https://www.onlinegdb.com/当我执行测试时,在第一种情况下,迭代器位置和 vector 开始之间的距离为 16 - 表明迭代器不再引用当前 vector 状态中的元素。在第二种情况下,距离为零 - 迭代器指的是新 vector 状态的开始。
如果
vals
的容量|在使用迭代器之前进行了扩展,例如:vals.reserve(10);
然后单个元素的插入不会导致内存移动,并且不会发生故障-尽管不更新迭代器并不是一个好主意-它只是指示引擎盖下发生的事情。
关于C++ 双重释放或损坏(出),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60248976/