谁能解释一下为什么我的程序在使用基于迭代器的for循环时崩溃,而在使用基于索引的for循环时不崩溃?我怀疑是因为基于索引的 for()
每次都会被评估,而基于迭代器的 for()
语句不知为何不是。
我试图在一个向量上循环,当到达最后一个元素并且是我要找的元素时,调整向量的大小,然后再添加一个元素。如果我使用的是 push_back
或 resize
.
这是玩具代码,作为一个例子,一个学习经验。我想知道为什么一个会崩溃,另一个不会。
下面的代码在调用向量的析构器时出现错误,导致崩溃 munmap_chunk(): invalid pointer
:
#include <iostream>
#include <vector>
int main() {
std::vector<int> exampleVector {0,1,2,3,4,5};
// iterator based loop
for (auto it = exampleVector.begin(); it != exampleVector.end(); ++it) {
if (*it == 5 && std::next(it) == exampleVector.end()) {
exampleVector.resize(exampleVector.size() + 1);
*std::next(it) = 999;
*it = 0;
}
}
return 0;
}
从Clion调试窗口复制的堆栈。
__GI_raise 0x00007f8cd892ce97
__GI_abort 0x00007f8cd892e801
__libc_message 0x00007f8cd8977897
malloc_printerr 0x00007f8cd897e90a
munmap_chunk 0x00007f8cd8985ecc
__GI___libc_free 0x00007f8cd8985ecc
__gnu_cxx::new_allocator<int>::deallocate new_allocator.h:125
std::allocator_traits<std::allocator<int> >::deallocate alloc_traits.h:462
std::_Vector_base<int, std::allocator<int> >::_M_deallocate stl_vector.h:180
std::_Vector_base<int, std::allocator<int> >::~_Vector_base stl_vector.h:162
std::vector<int, std::allocator<int> >::~vector stl_vector.h:435
main main.cpp:5
__libc_start_main 0x00007f8cd890fb97
_start 0x000055f736f6aaca
这个程序没有。
#includee <iostream>
#include <vector>
int main() {
std::vector<int> exampleVector {0,1,2,3,4,5};
// indexed for loop
for (size_t i = 0; i < exampleVector.size(); ++i) {
if (exampleVector.at(i) == 5 and exampleVector.at(i) == exampleVector.back()) {
exampleVector.resize(exampleVector.size() + 1);
exampleVector.at(i + 1) = 999;
exampleVector.at(i) = 0;
}
}
return 0;
}
在Ubuntu 18.04中,当你进行以下操作时,会得到默认的gcc版本: apt install build-essential
.
再次,寻找为什么一个崩溃而另一个不崩溃的原因。另外,这适用于基于范围的for循环吗?
当你调整一个 std::vector
,指向它的迭代器可能会失效。所以你需要重置 it
调整大小后。
if (*it == 5 && std::next(it) == exampleVector.end()) {
exampleVector.resize(exampleVector.size() + 1);
it = std::next(exampleVector.begin(), exampleVector.size() - 2);
// ...
}
很明显,索引只是 int
s,所以不存在关于它们变得无效的问题,所以你的第二个例子可以正常工作。
Range-for循环只是基于迭代器的循环的漂亮语法,所以是的,它会有和第一个版本一样的问题。