遍历vector容器时向其push元素报错的内部原因
遍历vector容器时向其push元素报错的内部原因
老哥,你碰到的这个问题,核心根源是在遍历vector的同时修改它的容量,导致迭代器失效,咱们掰开揉碎了说清楚:
首先先把你的代码贴出来方便对照:
class Solution { public: void func(vector<int>& nums, vector<vector<int>>& ans, int target){ if(target == -1){ vector<int> v; ans.push_back(v); return; } func(nums, ans, target - 1); for(auto x : ans){ x.push_back(nums[target]); ans.push_back(x); } } vector<vector<int>> subsets(vector<int>& nums) { vector<vector<int>> ans; func(nums, ans, nums.size() - 1); return ans; } };
问题出在哪?
你用for(auto x : ans)这种范围for循环遍历ans的时候,底层其实是依赖vector的迭代器来逐个访问元素的。而vector的底层实现是连续的内存数组,它有个固定的“容量”(可以理解为当前分配的内存能装多少元素)。当你调用ans.push_back(x)的时候,如果当前元素个数已经等于容量,vector就会触发扩容操作:
- 重新申请一块更大的连续内存空间(通常是原来的2倍)
- 把旧内存里的所有元素拷贝/移动到新内存
- 释放旧的内存空间
这时候麻烦就来了:原来用来遍历的迭代器,指向的是已经被释放的旧内存地址,变成了“野指针”。后续循环再用这个失效的迭代器去访问元素,就会触发未定义行为——可能直接报错,也可能程序崩溃,完全看运气。
而且还有个额外的问题:你在遍历的同时往容器里加元素,会导致循环次数远超预期,因为每次push都会让容器的size变大,循环会一直遍历新加入的元素,直到触发扩容崩溃。
怎么修复?
最简单的办法是先记录遍历前容器的元素个数,只遍历到这个固定的个数,用索引访问而不是依赖迭代器,这样就不会受后续push操作的影响:
void func(vector<int>& nums, vector<vector<int>>& ans, int target){ if(target == -1){ vector<int> v; ans.push_back(v); return; } func(nums, ans, target - 1); // 先记录当前ans的元素个数,只遍历这些旧元素 int old_size = ans.size(); for(int i = 0; i < old_size; i++){ vector<int> x = ans[i]; x.push_back(nums[target]); ans.push_back(x); } }
这样遍历的是扩容前的所有元素,不会碰到新加入的元素,也不会触发迭代器失效的问题,就能正常生成所有子集了。
备注:内容来源于stack exchange,提问作者ae80
相关产品推荐
相关产品推荐

