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

遍历std::list并删除元素时触发错误的原因与解决方法

std::list迭代时空指针解引用错误的原因与修复

问题代码

std::list<GameMatch*> games_;

void GameMatchManager::ClearEndedGames()
{
    if(games_.empty())
        return;

    auto it = games_.begin();
    while (it != games_.end())
    {
        auto game = *it;
        if(game->MatchEnded())
        {
            games_.erase(it);
            game->Destroy();
        }
        ++it;
    }
}

void GameMatch::Destroy()
{
    std::cout << "Destoying " << GetMatchId() << std::endl;
    delete this;
}

遇到的错误

空指针解引用错误

疑问:开头已经判断if(games_.empty()) return;,为什么还会触发空指针错误?这个判断不该阻止对空列表的迭代吗?


错误原因

  1. 迭代器失效导致非法访问
    调用games_.erase(it)后,当前迭代器it会直接失效。如果此时删除的是列表最后一个元素,erase后列表变为空,后续执行++it会让迭代器指向非法内存区域,循环条件it != games_.end()检查时就会触发空指针解引用错误。
  2. 开头的empty()判断仅在函数执行初期生效,迭代过程中列表可能被清空,这个判断无法覆盖迭代中的状态变化。

修复方案

方案一:利用erase的返回值更新迭代器(C++11+)

std::list::erase会返回指向被删除元素下一个位置的有效迭代器,用这个值更新迭代器即可避免失效问题:

void GameMatchManager::ClearEndedGames()
{
    auto it = games_.begin();
    while (it != games_.end())
    {
        auto game = *it;
        if(game->MatchEnded())
        {
            it = games_.erase(it); // 用erase返回的有效迭代器替换失效的it
            game->Destroy();
        }
        else
        {
            ++it; // 仅当未删除元素时才递增迭代器
        }
    }
}

此时开头的empty()判断可以直接移除——当列表为空时,begin()等于end(),循环会直接跳过,逻辑更简洁。

方案二:使用std::remove_if简化实现

借助STL算法remove_if可以更简洁地处理元素删除,内部会自动维护迭代器有效性:

#include <algorithm> // 需要包含algorithm头文件

void GameMatchManager::ClearEndedGames()
{
    games_.remove_if([](GameMatch* game) {
        if (game->MatchEnded()) {
            game->Destroy();
            return true; // 返回true表示该元素需要被移除
        }
        return false;
    });
}

这种写法更符合STL的设计思想,代码可读性和安全性更高。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 03:10:11