List容器:特性与操作使用指南
目录
一、List(链表)容器的详细介绍
1、基本特性
2、与 forward_list 的比较
3、性能特点
优势:
劣势:
4、适用场景
5、实现细节
二、list的定义方式
1、构造空容器
2、构造含n个val的容器
3、拷贝构造容器
4、使用迭代器范围构造
5、使用数组区间构造
6、移动构造(C++11)
7、初始化列表构造(C++11)
三、List 的插入和删除操作
1、头插和头删操作
push_front 和 pop_front
2、尾插和尾删操作
push_back 和 pop_back
3、插入操作
insert 函数
4、删除操作
erase 函数
总结
四、List迭代器的使用
1、正向迭代器
正向迭代器遍历示例
注意事项
2、反向迭代器
反向迭代器遍历示例
注意事项
3、迭代器使用场景
4、C++11后的简化写法
总结
五、List容器的首尾元素访问
1、front() 和 back() 函数
2、示例代码
3、注意事项
4、修改元素示例
六、list容器的大小控制方法
1、size() - 获取元素数量
2、resize() - 调整容器大小
3、empty() - 检查容器是否为空
4、clear() - 清空容器
总结
七、list容器操作函数
1、sort函数
2、splice函数
3、remove和remove_if函数
4、unique函数
5、merge函数
6、reverse函数
7、assign函数
8、swap函数
八、List迭代器失效问题
1、迭代器失效的概念
2、List迭代器失效的特点
3、错误示例分析
4、正确解决方案
方案1:利用后置++的特性
erase(it++) 的执行流程
具体例子
关键点
方案2:使用erase的返回值
一、List(链表)容器的详细介绍
List 是 C++ 标准模板库(STL)中的一种序列式容器,具有以下核心特性:
1、基本特性
-
支持在常数时间 O(1) 范围内进行任意位置的插入和删除操作
-
提供前后双向迭代的能力(双向链表结构)
-
底层采用双向链表实现,每个元素存储在独立的节点中
-
各节点通过前驱和后继指针相互连接
2、与 forward_list 的比较
与单向链表 forward_list 的主要区别:
-
双向迭代 vs 单向迭代
-
更完善的操作接口(forward_list 为节省内存牺牲了部分功能)
3、性能特点
优势:
-
任意位置插入/删除效率极高(无需移动其他元素)
-
拼接操作(splice)性能优异
劣势:
-
不支持随机访问(无法使用 [] 运算符)
-
需要额外存储空间维护节点关系
-
对缓存局部性(cache locality)不友好
4、适用场景
-
需要频繁在序列中间进行插入/删除操作
-
不需要随机访问元素
-
需要高效的大型序列拼接操作
-
元素体积较大时,链表的内存开销相对较小
5、实现细节
-
通常采用环状双向链表实现
-
每个节点包含:数据域、前驱指针、后继指针
-
可能包含一个哨兵节点(dummy node)简化边界条件处理
注意:当存储小型元素且不需要频繁中间操作时,vector 通常能提供更好的综合性能。选择容器时应根据具体使用场景权衡利弊。
二、list的定义方式
list是C++标准模板库(STL)中的一个双向链表容器,提供了多种灵活的构造方式。以下是list的几种主要定义方式:
1、构造空容器
最基本的构造方式,创建一个指定类型的空链表容器。
list<int> lt1; // 构造一个int类型的空链表
2、构造含n个val的容器
创建一个包含n个相同元素的链表。
list<int> lt2(10, 2); // 构造含有10个值为2的int类型链表
3、拷贝构造容器
通过另一个同类型list容器进行拷贝构造。
list<int> lt3(lt2); // 使用lt2拷贝构造一个新的int类型链表lt3
4、使用迭代器范围构造
通过其他容器的迭代器范围来构造链表。
string s("hello world");
list<char> lt4(s.begin(), s.end()); // 使用string的迭代器范围构造char类型链表
5、使用数组区间构造
通过原生数组的区间来构造链表。
int arr[] = {1, 2, 3, 4, 5};
int sz = sizeof(arr) / sizeof(int);
list<int> lt5(arr, arr + sz); // 使用数组区间构造int类型链表
6、移动构造(C++11)
使用移动语义构造链表,高效转移资源所有权。
list<int> temp = {1, 2, 3};
list<int> lt6(std::move(temp)); // 移动构造,temp现在为空
7、初始化列表构造(C++11)
使用初始化列表直接构造链表。
list<int> lt7 = {1, 2, 3, 4, 5}; // 使用初始化列表构造
这些构造方式提供了极大的灵活性,可以根据不同场景选择最合适的初始化方法。
三、List 的插入和删除操作
1、头插和头删操作
push_front
和 pop_front
push_front
函数用于在链表头部插入一个元素,pop_front
函数用于删除链表头部的元素。
#include <iostream>
#include <list>
using namespace std;int main()
{list<int> lt;// 头部插入元素lt.push_front(0);lt.push_front(1);lt.push_front(2);// 输出当前链表内容for (auto e : lt) {cout << e << " ";}cout << endl; // 输出: 2 1 0// 头部删除元素lt.pop_front();// 输出删除后的链表内容for (auto e : lt) {cout << e << " ";}cout << endl; // 输出: 1 0return 0;
}
2、尾插和尾删操作
push_back
和 pop_back
push_back
函数用于在链表尾部插入一个元素,pop_back
函数用于删除链表尾部的元素。
#include <iostream>
#include <list>
using namespace std;int main()
{list<int> lt;// 尾部插入元素lt.push_back(0);lt.push_back(1);lt.push_back(2);lt.push_back(3);// 输出当前链表内容for (auto e : lt) {cout << e << " ";}cout << endl; // 输出: 0 1 2 3// 尾部删除元素(删除两次)lt.pop_back();lt.pop_back();// 输出删除后的链表内容for (auto e : lt) {cout << e << " ";}cout << endl; // 输出: 0 1return 0;
}
3、插入操作
insert
函数
list
的 insert
函数支持三种插入方式:
-
在指定迭代器位置插入一个元素
-
在指定迭代器位置插入 n 个值为 val 的元素
-
在指定迭代器位置插入一段迭代器区间(左闭右开)
#include <iostream>
#include <algorithm>
#include <vector>
#include <list>
using namespace std;int main()
{list<int> lt;lt.push_back(1);lt.push_back(2);lt.push_back(3);// 在值为2的位置插入9list<int>::iterator pos = find(lt.begin(), lt.end(), 2);lt.insert(pos, 9);for (auto e : lt) {cout << e << " ";}cout << endl; // 输出: 1 9 2 3// 在值为3的位置插入2个8pos = find(lt.begin(), lt.end(), 3);lt.insert(pos, 2, 8);for (auto e : lt) {cout << e << " ";}cout << endl; // 输出: 1 9 2 8 8 3// 在值为1的位置插入vector中的元素vector<int> v(2, 7); // 包含两个7的vectorpos = find(lt.begin(), lt.end(), 1);lt.insert(pos, v.begin(), v.end());for (auto e : lt) {cout << e << " ";}cout << endl; // 输出: 7 7 1 9 2 8 8 3return 0;
}
注意:
find
函数是<algorithm>
头文件中的一个函数,用于在指定迭代器区间查找指定值的位置,并返回该位置的迭代器。如果未找到,则返回结束迭代器。
4、删除操作
erase
函数
list
的 erase
函数支持两种删除方式:
-
删除指定迭代器位置的元素
-
删除指定迭代器区间(左闭右开)的所有元素
#include <iostream>
#include <algorithm>
#include <vector>
#include <list>
using namespace std;int main()
{list<int> lt;lt.push_back(1);lt.push_back(2);lt.push_back(3);lt.push_back(4);lt.push_back(5);// 删除值为2的元素list<int>::iterator pos = find(lt.begin(), lt.end(), 2);lt.erase(pos);for (auto e : lt) {cout << e << " ";}cout << endl; // 输出: 1 3 4 5// 删除从值为4的元素到末尾的所有元素pos = find(lt.begin(), lt.end(), 4);lt.erase(pos, lt.end());for (auto e : lt) {cout << e << " ";}cout << endl; // 输出: 1 3return 0;
}
总结
-
头部操作:
push_front
和pop_front
提供了高效的头部插入和删除 -
尾部操作:
push_back
和pop_back
提供了高效的尾部插入和删除 -
任意位置操作:
insert
和erase
提供了在任意位置插入和删除元素的能力 -
性能特点:由于
list
是双向链表,所有插入和删除操作的时间复杂度都是 O(1)(前提是已经获得正确位置的迭代器)
这些操作使得 list
在需要频繁插入和删除元素的场景中表现出色。
四、List迭代器的使用
可暂时将迭代器理解成一个指针,该指针指向list中的某个节点。
1、正向迭代器
list容器的正向迭代器通过begin()
和end()
函数获得:
-
begin()
: 返回指向容器中第一个元素的正向迭代器 -
end()
: 返回指向容器中最后一个元素的下一个位置的正向迭代器(不是最后一个元素)
正向迭代器遍历示例
#include <iostream>
#include <list>
using namespace std;int main()
{list<int> lt(10, 2); // 创建包含10个值为2的元素的list// 使用正向迭代器遍历容器list<int>::iterator it = lt.begin();while (it != lt.end()){cout << *it << " ";it++;}cout << endl;return 0;
}
输出结果:
注意事项
-
end()
返回的是"尾后迭代器",不能解引用 -
迭代器支持
++
操作来移动到下一个元素 -
可以用
*
操作符访问当前元素的值
2、反向迭代器
list容器的反向迭代器通过rbegin()
和rend()
函数获得:
-
rbegin()
: 返回指向容器中最后一个元素的反向迭代器 -
rend()
: 返回指向容器中第一个元素的前一个位置的反向迭代器
反向迭代器遍历示例
#include <iostream>
#include <list>
using namespace std;int main()
{list<int> lt(10, 2); // 创建包含10个值为2的元素的list// 使用反向迭代器遍历容器list<int>::reverse_iterator rit = lt.rbegin();while (rit != lt.rend()){cout << *rit << " ";rit++;}cout << endl;return 0;
}
输出结果:
注意事项
-
反向迭代器的
++
操作实际上是向容器的前端移动 -
rend()
返回的是"首前迭代器",不能解引用 -
反向迭代器也需要用
*
操作符访问当前元素的值
3、迭代器使用场景
-
遍历容器:如上面示例所示
-
插入元素:使用
insert()
函数结合迭代器在特定位置插入元素 -
删除元素:使用
erase()
函数结合迭代器删除特定位置的元素 -
算法操作:与STL算法配合使用,如
sort()
,find()
等
4、C++11后的简化写法
C++11引入了auto
关键字,可以简化迭代器声明:
// 正向迭代器
for(auto it = lt.begin(); it != lt.end(); ++it) {cout << *it << " ";
}// 反向迭代器
for(auto rit = lt.rbegin(); rit != lt.rend(); ++rit) {cout << *rit << " ";
}// 范围for循环(C++11)
for(const auto& val : lt) {cout << val << " ";
}
总结
list的迭代器提供了灵活访问容器元素的方式,正向迭代器适合从前向后遍历,反向迭代器适合从后向前遍历。理解迭代器的概念对于有效使用STL容器至关重要。
五、List容器的首尾元素访问
在C++ STL中,list容器提供了两个便捷的成员函数来访问首尾元素:
1、front() 和 back() 函数
-
front()
: 返回list容器中的第一个元素的引用 -
back()
: 返回list容器中的最后一个元素的引用
这两个函数的时间复杂度都是O(1),因为它们直接访问list的头尾节点,不需要遍历整个容器。
2、示例代码
#include <iostream>
#include <list>
using namespace std;int main()
{// 创建一个整型list并初始化list<int> lt;lt.push_back(0); // 添加元素0lt.push_back(1); // 添加元素1lt.push_back(2); // 添加元素2lt.push_back(3); // 添加元素3lt.push_back(4); // 添加元素4// 输出第一个和最后一个元素cout << "第一个元素: " << lt.front() << endl; // 输出: 0cout << "最后一个元素: " << lt.back() << endl; // 输出: 4return 0;
}
3、注意事项
-
在调用
front()
或back()
前,应确保list不为空,否则会导致未定义行为 -
这两个函数返回的是引用,因此可以直接修改元素值
-
如果需要检查list是否为空,可以使用
empty()
成员函数
4、修改元素示例
lt.front() = 10; // 将第一个元素改为10
lt.back() = 40; // 将最后一个元素改为40
这种直接访问首尾元素的方式使得list在某些场景下(如实现队列)非常高效。
六、list容器的大小控制方法
list是C++ STL中的一个双向链表容器,提供了多种方法来控制和查询容器的大小。下面详细介绍这些方法及其使用。
1、size() - 获取元素数量
size()
函数返回当前list容器中的元素个数。
#include <iostream>
#include <list>
using namespace std;int main()
{list<int> lt;lt.push_back(1);lt.push_back(2);lt.push_back(3);lt.push_back(4);cout << "当前list中的元素数量: " << lt.size() << endl; // 输出: 4return 0;
}
2、resize() - 调整容器大小
resize()
函数用于改变list的大小,有两种情况:
-
当新大小大于当前size时,将size扩大到该值,新增元素为第二个参数值(若未提供则使用默认值0)
-
当新大小小于当前size时,将size缩小到该值,多余元素被删除
#include <iostream>
#include <list>
using namespace std;void printList(const list<int>& lt) {for (auto e : lt) {cout << e << " ";}cout << endl;
}int main()
{// 初始化list,包含5个值为3的元素list<int> lt(5, 3);printList(lt); // 输出: 3 3 3 3 3// 扩大list大小为7,新增元素值为6lt.resize(7, 6);printList(lt); // 输出: 3 3 3 3 3 6 6// 缩小list大小为2lt.resize(2);printList(lt); // 输出: 3 3// 扩大list但不指定新增元素值,使用int默认值0lt.resize(5);printList(lt); // 输出: 3 3 0 0 0return 0;
}
3、empty() - 检查容器是否为空
empty()
函数返回一个布尔值,表示容器是否为空(size为0)。
#include <iostream>
#include <list>
using namespace std;int main()
{list<int> lt;cout << "list是否为空? " << (lt.empty() ? "是" : "否") << endl; // 输出: 是lt.push_back(10);cout << "list是否为空? " << (lt.empty() ? "是" : "否") << endl; // 输出: 否return 0;
}
4、clear() - 清空容器
clear()
函数删除容器中的所有元素,使size变为0。
#include <iostream>
#include <list>
using namespace std;void printListInfo(const list<int>& lt) {cout << "元素: ";for (auto e : lt) {cout << e << " ";}cout << "\n大小: " << lt.size() << endl;
}int main()
{list<int> lt(5, 2); // 5个值为2的元素printListInfo(lt);/* 输出:元素: 2 2 2 2 2 大小: 5*/lt.clear(); // 清空容器printListInfo(lt);/* 输出:元素: 大小: 0*/return 0;
}
总结
方法 | 功能描述 | 时间复杂度 |
---|---|---|
size() | 返回容器中的元素数量 | O(1) |
resize(n) | 调整容器大小为n | O(n-size) |
empty() | 检查容器是否为空 | O(1) |
clear() | 删除所有元素,size变为0 | O(n) |
这些方法为list容器提供了灵活的大小控制能力,可以根据需要动态调整容器大小或查询容器状态。
七、list容器操作函数
list是C++标准模板库(STL)中的一个双向链表容器,提供了多种操作函数来高效地管理数据。下面详细介绍list的各种常用操作函数。
1、sort函数
sort函数用于对list容器中的元素进行排序,默认按升序排列。
#include <iostream>
#include <list>
using namespace std;int main() {list<int> lt = {4, 7, 5, 9, 6, 0, 3};cout << "排序前: ";for (auto e : lt) cout << e << " "; // 输出: 4 7 5 9 6 0 3cout << endl;lt.sort(); // 默认升序排序cout << "排序后: ";for (auto e : lt) cout << e << " "; // 输出: 0 3 4 5 6 7 9cout << endl;return 0;
}
2、splice函数
splice函数用于两个list容器之间的拼接,有三种使用方式:
-
将整个容器拼接到另一个容器的指定位置
-
将容器中的某个元素拼接到另一个容器的指定位置
-
将容器指定区间的元素拼接到另一个容器的指定位置
#include <iostream>
#include <list>
using namespace std;int main() {// 1. 整个容器拼接list<int> lt1(4, 2);list<int> lt2(4, 6);lt1.splice(lt1.begin(), lt2); // 将lt2拼接到lt1开头cout << "整个容器拼接结果: ";for (auto e : lt1) cout << e << " "; // 输出: 6 6 6 6 2 2 2 2cout << endl;// 2. 单个元素拼接list<int> lt3(4, 2);list<int> lt4(4, 6);lt3.splice(lt3.begin(), lt4, lt4.begin()); // 将lt4的第一个元素拼接到lt3开头cout << "单个元素拼接结果: ";for (auto e : lt3) cout << e << " "; // 输出: 6 2 2 2 2cout << endl;// 3. 区间元素拼接list<int> lt5(4, 2);list<int> lt6(4, 6);lt5.splice(lt5.begin(), lt6, lt6.begin(), lt6.end()); // 将lt6的全部元素拼接到lt5开头cout << "区间元素拼接结果: ";for (auto e : lt5) cout << e << " "; // 输出: 6 6 6 6 2 2 2 2cout << endl;return 0;
}
注意:容器当中被拼接到另一个容器的数据在原容器当中就不存在了。(实际上就是将链表当中的指定结点拼接到了另一个容器当中)
3、remove和remove_if函数
remove函数删除容器中所有等于指定值的元素;remove_if函数删除满足特定条件的元素。
#include <iostream>
#include <list>
using namespace std;bool is_single_digit(const int& val) {return val < 10;
}int main() {// remove示例list<int> lt = {1, 4, 3, 3, 2, 2, 3};cout << "remove前: ";for (auto e : lt) cout << e << " "; // 输出: 1 4 3 3 2 2 3cout << endl;lt.remove(3); // 删除所有值为3的元素cout << "remove后: ";for (auto e : lt) cout << e << " "; // 输出: 1 4 2 2cout << endl;// remove_if示例list<int> lt2 = {10, 4, 7, 18, 2, 5, 9};cout << "remove_if前: ";for (auto e : lt2) cout << e << " "; // 输出: 10 4 7 18 2 5 9cout << endl;lt2.remove_if(is_single_digit); // 删除所有小于10的元素cout << "remove_if后: ";for (auto e : lt2) cout << e << " "; // 输出: 10 18cout << endl;return 0;
}
4、unique函数
unique函数删除容器中连续的重复元素。通常需要先排序才能实现完全去重。
#include <iostream>
#include <list>
using namespace std;int main() {list<int> lt = {1, 4, 3, 3, 2, 2, 3};cout << "原始数据: ";for (auto e : lt) cout << e << " "; // 输出: 1 4 3 3 2 2 3cout << endl;lt.sort(); // 先排序lt.unique(); // 再去重cout << "去重后: ";for (auto e : lt) cout << e << " "; // 输出: 1 2 3 4cout << endl;return 0;
}
5、merge函数
merge函数用于合并两个已排序的list容器,合并后仍然保持有序。(类似于归并排序)
#include <iostream>
#include <list>
using namespace std;int main() {list<int> lt1 = {3, 8, 1};list<int> lt2 = {6, 2, 9, 5};lt1.sort(); // 排序lt1: 1, 3, 8lt2.sort(); // 排序lt2: 2, 5, 6, 9lt1.merge(lt2); // 合并lt2到lt1cout << "合并后结果: ";for (auto e : lt1) cout << e << " "; // 输出: 1 2 3 5 6 8 9cout << endl;return 0;
}
6、reverse函数
reverse函数用于反转容器中元素的顺序。
#include <iostream>
#include <list>
using namespace std;int main() {list<int> lt = {1, 2, 3, 4, 5};cout << "反转前: ";for (auto e : lt) cout << e << " "; // 输出: 1 2 3 4 5cout << endl;lt.reverse(); // 反转元素顺序cout << "反转后: ";for (auto e : lt) cout << e << " "; // 输出: 5 4 3 2 1cout << endl;return 0;
}
7、assign函数
assign函数用于替换容器中的内容,有两种方式:
-
用n个值为val的元素替换
-
用迭代器区间内的元素替换
#include <iostream>
#include <string>
#include <list>
using namespace std;int main() {// 方式1: 用n个值替换list<char> lt(3, 'a');lt.assign(3, 'b'); // 用3个'b'替换原有内容cout << "assign方式1: ";for (auto e : lt) cout << e << " "; // 输出: b b bcout << endl;// 方式2: 用迭代器区间替换string s("hello world");lt.assign(s.begin(), s.end()); // 用字符串内容替换cout << "assign方式2: ";for (auto e : lt) cout << e << " "; // 输出: h e l l o w o r l dcout << endl;return 0;
}
8、swap函数
swap函数用于交换两个容器的内容。
#include <iostream>
#include <list>
using namespace std;int main() {list<int> lt1(4, 2);list<int> lt2(4, 6);lt1.swap(lt2); // 交换两个容器的内容cout << "lt1交换后: ";for (auto e : lt1) cout << e << " "; // 输出: 6 6 6 6cout << endl;cout << "lt2交换后: ";for (auto e : lt2) cout << e << " "; // 输出: 2 2 2 2cout << endl;return 0;
}
八、List迭代器失效问题
1、迭代器失效的概念
迭代器可以简单理解为一种智能指针,它提供了访问容器元素的统一接口。当迭代器指向的容器元素变得无效时,就发生了迭代器失效。对于list而言,迭代器失效特指迭代器所指向的节点被删除,导致该迭代器无法继续使用的情况。
2、List迭代器失效的特点
由于list的底层实现是带头节点的双向循环链表,它具有以下特性:
-
插入操作:不会导致任何迭代器失效,因为新节点的加入不会影响已有节点的内存地址
-
删除操作:只会使指向被删除节点的迭代器失效,其他迭代器不受影响
3、错误示例分析
void TestListIterator1() {int array[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0};list<int> l(array, array + sizeof(array) / sizeof(array[0]));auto it = l.begin();while (it != l.end()) {// 错误:erase()后it已失效,再执行++it是未定义行为l.erase(it); ++it;}
}
上述代码的问题在于:
-
erase(it)
调用后,it指向的节点已被删除 -
对已失效的迭代器执行
++it
操作会导致未定义行为 -
程序可能会崩溃或产生不可预测的结果
4、正确解决方案
方案1:利用后置++的特性
void TestListIterator() {int array[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0};list<int> l(array, array + sizeof(array) / sizeof(array[0]));auto it = l.begin();while (it != l.end()) {l.erase(it++); // 先传递it的副本,再递增it}
}
erase(it++)
的执行流程
-
it++
的语义:-
it++
是后置递增操作,它的行为是:-
先返回
it
的当前值(副本) -
然后递增
it
本身(指向下一个元素)
-
-
所以
erase(it++)
实际上是:-
先传递
it
的原始值(副本)给erase
-
然后
it
自身递增,指向下一个元素
-
-
-
erase
的作用:-
erase
删除的是传入的迭代器指向的节点,也就是it
的副本指向的元素 -
由于
it
自身已经被递增,所以它现在指向的是下一个有效节点,而不是被删除的节点
-
具体例子
假设初始 list
是 {1, 2, 3}
,it
初始指向 1
:
-
第一次循环:
-
erase(it++)
:-
传递给
erase
的是it
的副本(指向1
) -
it
自身递增,现在指向2
-
erase
删除1
,但it
已经指向2
,所以不会失效
-
-
现在
list
是{2, 3}
,it
指向2
-
-
第二次循环:
-
erase(it++)
:-
传递给
erase
的是it
的副本(指向2
) -
it
自身递增,现在指向3
-
erase
删除2
,但it
已经指向3
,所以不会失效
-
-
现在
list
是{3}
,it
指向3
-
-
第三次循环:
-
erase(it++)
:-
传递给
erase
的是it
的副本(指向3
) -
it
自身递增,现在指向end()
-
erase
删除3
,it
已经指向end()
,循环终止
-
-
关键点
-
erase
删除的是副本指向的节点,不是it
当前指向的节点 -
it
自身在erase
之前就已经递增,所以不会失效 -
这种方式避免了
erase
后it
变成野指针的问题
方案2:使用erase的返回值
void TestListIterator() {int array[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0};list<int> l(array, array + sizeof(array) / sizeof(array[0]));auto it = l.begin();while (it != l.end()) {it = l.erase(it); // erase返回被删除元素的下一个有效迭代器}
}
-
erase
会返回被删除元素的下一个有效迭代器 -
这样代码更易读,且适用于所有标准库容器(如
vector
、deque
等)
两种解决方案都能正确处理list的迭代器失效问题,推荐使用第二种方案,因为:
-
代码意图更明确
-
不依赖于后置++的求值顺序
-
与其他STL容器的erase操作保持一致性