You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++遍历删除std::vector元素时注释指定行引发崩溃的原因

问题描述

完成LeetCode字母异位词分组题目时,下述代码可正常运行,但注释掉代码中标注的break行后程序会崩溃,初步判断问题与std::vector的遍历、删除操作相关。

class Solution {
public:
    vector<vector<string>> groupAnagrams(vector<string>& strs) {

        vector<vector<string>> ans;

        while (strs.size() > 0)
        {
            string tmp1 = strs[0];

            vector<string> tmpAns{ tmp1 };
            strs.erase(strs.begin());          
            sort(tmp1.begin(), tmp1.end());

            auto itr = strs.begin();
            while (itr != strs.end())
            {
                string tmp2 = *itr;
                sort(tmp2.begin(), tmp2.end());

                if (tmp2 == tmp1)
                {
                    tmpAns.push_back(*itr);
                    strs.erase(itr);

                    if (strs.size() <= 0) break; // 注释掉这行就会崩溃
                }
                else
                {
                    ++itr;
                }
            }

            ans.push_back(tmpAns);
        }

        return ans;
    }
};

int main()
{
    Solution s;
    vector<string> in= vector<string>{"a", "a"};

    vector<vector<string>> ans = s.groupAnagrams(in);

    std::cout << "Hello World!\n";
}
崩溃根本原因

核心问题是错误使用了std::vectorerase操作后的失效迭代器:

  • std::vector是连续内存存储的容器,调用erase(iterator pos)删除元素时,传入的pos迭代器会直接失效,同时该函数会返回被删除元素下一个位置的有效迭代器。
  • 代码里执行strs.erase(itr)后,没有接收返回的有效迭代器,旧的itr已经变成野迭代器,对野迭代器做任何操作(包括和strs.end()比较、解引用)都是未定义行为,必然可能触发崩溃。

用测试用例{"a","a"}走一遍流程就能复现崩溃:

  1. 外层循环首次进入时,strs长度为2,取出第一个"a"存入临时结果,删除首元素后strs仅剩1个"a"。
  2. 内层循环的itr指向剩下的那个"a",排序比对后匹配异位词,执行strs.erase(itr),此时strs长度变为0,itr彻底失效。
  3. 如果没有那行break,代码会回到内层循环的判断条件itr != strs.end(),此时用失效的itr和end()做比较,直接触发崩溃。

注意:那行判断size后break的代码只是刚好在「删除最后一个元素后strs为空」的场景下,跳过了后续使用失效迭代器的逻辑,属于歪打正着的补丁,没有从根上解决迭代器失效问题。如果遇到删除非末尾元素的场景,就算保留这行break,后续循环依然会使用失效迭代器,崩溃概率极高。

正确修复方案

删除那行临时补丁的break,在erase元素时直接接收函数返回的有效迭代器即可,修改后的内层循环代码如下:

auto itr = strs.begin();
while (itr != strs.end())
{
    string tmp2 = *itr;
    sort(tmp2.begin(), tmp2.end());

    if (tmp2 == tmp1)
    {
        tmpAns.push_back(*itr);
        itr = strs.erase(itr); // 接收erase返回的下一个位置的有效迭代器
    }
    else
    {
        ++itr;
    }
}

这种写法完全符合STL容器迭代器的使用规范,不管删除的是哪个位置的元素,迭代器始终保持有效,不会触发未定义行为。

内容的提问来源于stack exchange,提问作者Charlie

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 13:57:08