使用std::remove_if删除deque指定条目时出现残留元素,问题出在哪里?
错误原因
你没有正确使用erase的区间重载,这是erase-remove惯用法的常见易错点。
具体逻辑拆解
- 首先明确你的
error_codes初始顺序:你连续调用三次push_front插入元素,最终初始队列是{STATUS_TEST(3), STATUS_NOT_OK(2), STATUS_OK(1)}。 std::remove_if的作用是将不需要删除的元素移动到序列前部,返回值是「新的逻辑末尾迭代器」,也就是最后一个保留元素的下一个位置。你的场景中需要保留的只有3,所以remove_if返回的迭代器指向存储2的位置。- 你出问题的版本只给
erase传了这一个迭代器,erase的单参数重载只会删除这个迭代器指向的单个元素(也就是2),所以最终剩下{3,1},和你遇到的现象完全吻合。如果额外加一个STATUS_NOT_OK,remove_if返回的迭代器指向第一个2的位置,单参数erase只会删这一个2,剩下的就是{3,2,1},也符合你的测试结果。
修正方案
调用erase时传入两个参数,第一个是remove_if的返回值,第二个是容器的end()迭代器,这样就会把remove_if返回位置到容器末尾的所有待删除元素全部清除:
error_codes.erase( std::remove_if( begin(error_codes), end(error_codes), [&ignored_codes](int32_t error_code) { // 这里也可以用std::find简化手写循环 return std::find(ignored_codes.begin(), ignored_codes.end(), error_code) != ignored_codes.end(); } ), end(error_codes) // 这个参数是必须的 );
修正后error_codes最终只会保留{3},符合预期。
优化建议
如果ignored_codes的元素数量较多,可以把std::list换成std::unordered_set,查找时间复杂度可以从O(n)降到O(1),效率更高。
内容的提问来源于stack exchange,提问作者Jason
相关产品推荐
相关产品推荐

