调用clear()后使用std::vector迭代器为何仍能正常运行?
为什么vector::clear()后访问旧迭代器仍能正常运行?
我遇到一个反常现象:调用std::vector::clear()后,访问之前获取的迭代器,理论上这是无效操作,但实际代码却能正常运行,对此我很疑惑。
我的代码如下:
#include <iostream> #include <thread> #include <chrono> #include <string> #include <vector> struct Data { Data(const char * d) :data(d){} std::string data; }; // 使用这些数据以尽快避免SOO(aka small object optimize) std::vector<Data> arr {"11111111111111111111111111111111111111111111111111111111", "2222222222222222222222222222222222222222222222222222222", "3333333333333333333333333333333333333333333333333333333", "4444444444444444444444444444444444444444444444444444444", "5555555555555555555555555555555555555555555555555555555"}; class Test { public: void test() { // 先获取一个有效的迭代器 std::vector<Data>::iterator it = arr.begin(); // 启动一个线程清空arr std::thread([](){ std::this_thread::sleep_for(std::chrono::seconds(2)); arr.clear(); }).detach(); // 休眠3秒确保后续代码在线程之后运行 std::this_thread::sleep_for(std::chrono::seconds(3)); // 我认为it->data是无效操作,但它却能正常运行:( std::string res = it->data; } }; int main() { Test test; test.test(); std::this_thread::sleep_for(std::chrono::seconds(5)); return 0; }
原因解析
迭代器失效是标准规定的未定义行为
C++标准明确指出:调用vector::clear()后,所有指向容器元素的迭代器、指针和引用都会失效。此时访问这些迭代器属于未定义行为——未定义行为不等于一定会崩溃,它的结果完全不可预测,你的代码只是刚好表现为“正常运行”。clear()不释放底层内存
vector::clear()的作用仅为销毁容器内的所有元素,并将size()置为0,但不会释放底层已分配的内存(capacity()保持原值)。也就是说,原来存储元素的内存空间并没有被操作系统回收,只是vector不再将这块区域视为有效元素的存储区。内存未被覆盖的巧合
你的Data对象中的std::string因为使用了长字符串,避开了小对象优化,实际数据存储在堆上。当Data被销毁时,string的析构函数会释放自己的堆内存,但你访问的it->data指向的是原vector元素的内存位置——虽然Data对象已销毁,但这块内存暂时还没被其他操作覆盖,读取到的是string对象残留的指针值;而刚好对应的堆内存也还没被重新分配,所以能读到旧数据。
这种情况完全是巧合,只要更换编译器、调整优化级别,或者在clear()后执行其他内存分配操作,大概率会出现崩溃、乱码等异常结果,绝对不能依赖这种行为编写代码。
内容的提问来源于stack exchange,提问作者mac.ma
相关产品推荐
相关产品推荐

