C++ STL 中 insert() 函数详解:从 vector 到 string、set、map 的插入操作
一、前言
在 C++ STL 中,insert() 是一个非常常见的成员函数,主要用于向容器中插入元素。不同容器中的 insert() 用法不完全相同,例如 vector 可以在指定位置插入元素,string 可以在指定下标插入字符串,set 和 map 则会按照自身规则插入数据。
本文将从最常见的 vector::insert() 入手,再扩展到 string、set、map 等常见容器,帮助大家系统掌握 C++ 中 insert() 的使用方法。
参考资料中提到,vector 容器提供了 insert() 和 emplace() 两个成员函数,二者都可以在指定位置插入元素,但 emplace() 是 C++11 新增的函数,通常可以直接在容器内部构造对象。(C语言中文网)
二、insert() 是什么?
insert() 的英文含义是“插入”。
在 C++ STL 中,insert() 通常是容器的成员函数,用来向容器中添加一个或多个元素。
常见支持 insert() 的容器有:
vector
string
list
deque
set
map
unordered_set
unordered_map
虽然它们都叫 insert(),但由于容器底层结构不同,具体用法和返回值也有所区别。
例如:
vector<int> v;
v.insert(v.begin(), 10);
这行代码表示:在 vector 的开头位置插入一个整数 10。
三、vector 中 insert() 的基本用法
vector 是最常见的顺序容器之一。它的特点是元素连续存储,可以通过下标快速访问。
在 vector 中,insert() 的作用是:
在指定迭代器位置之前插入元素。
注意,是“之前”,不是“之后”。
例如:
v.insert(v.begin() + 1, 100);
表示在下标为 1 的元素前面插入 100。
四、vector::insert() 的几种常见形式
1. 插入单个元素
语法:
iterator insert(iterator pos, const T& value);
含义:
在 pos 指向的位置之前插入一个元素 value。
示例代码:
#include <iostream>
#include <vector>
using namespace std;
int main() {
vector<int> v = {1, 2, 3, 4};
v.insert(v.begin() + 2, 100);
for (int x : v) {
cout << x << " ";
}
return 0;
}
运行结果:
1 2 100 3 4
代码分析:
原数组为:
1 2 3 4
v.begin() + 2 指向元素 3,所以 100 会被插入到 3 的前面。
最终结果为:
1 2 100 3 4
2. 插入多个相同元素
语法:
iterator insert(iterator pos, int count, const T& value);
含义:
在 pos 位置之前插入 count 个相同的 value。
示例代码:
#include <iostream>
#include <vector>
using namespace std;
int main() {
vector<int> v = {1, 2, 3};
v.insert(v.begin() + 1, 3, 9);
for (int x : v) {
cout << x << " ";
}
return 0;
}
运行结果:
1 9 9 9 2 3
代码分析:
v.begin() + 1 指向元素 2。
所以代码会在 2 前面插入三个 9。
3. 插入另一个容器的一段元素
语法:
iterator insert(iterator pos, first, last);
含义:
将 [first, last) 范围内的元素插入到 pos 位置之前。
这里的 [first, last) 是左闭右开区间,也就是说包含 first,不包含 last。
示例代码:
#include <iostream>
#include <vector>
using namespace std;
int main() {
vector<int> v1 = {1, 2, 3};
vector<int> v2 = {10, 20, 30};
v1.insert(v1.end(), v2.begin(), v2.end());
for (int x : v1) {
cout << x << " ";
}
return 0;
}
运行结果:
1 2 3 10 20 30
代码分析:
v1.end() 表示 v1 的末尾位置。
所以这段代码相当于把 v2 中的所有元素插入到 v1 的末尾。
4. 使用初始化列表插入多个元素
语法:
iterator insert(iterator pos, initializer_list<T> list);
示例代码:
#include <iostream>
#include <vector>
using namespace std;
int main() {
vector<int> v = {1, 2, 3};
v.insert(v.begin() + 1, {100, 200, 300});
for (int x : v) {
cout << x << " ";
}
return 0;
}
运行结果:
1 100 200 300 2 3
代码分析:
这段代码在元素 2 的前面插入了:
100 200 300
所以最终结果为:
1 100 200 300 2 3
vector::insert() 支持插入单个元素、多个相同元素、迭代器区间以及初始化列表等形式。cppreference 对 vector::insert() 的说明中也列出了这些常见重载形式,包括插入单个值、插入多个副本、插入 [first, last) 范围内的元素等。(CPP参考)
五、vector::insert() 完整示例
下面用一个完整程序演示 vector 中 insert() 的多种用法。
#include <iostream>
#include <vector>
#include <array>
using namespace std;
int main() {
vector<int> v = {1, 2};
// 1. 插入单个元素
v.insert(v.begin() + 1, 3);
// 2. 插入多个相同元素
v.insert(v.end(), 2, 5);
// 3. 插入另一个容器中的一段元素
array<int, 3> arr = {7, 8, 9};
v.insert(v.end(), arr.begin(), arr.end());
// 4. 使用初始化列表插入元素
v.insert(v.end(), {10, 11});
for (int x : v) {
cout << x << " ";
}
return 0;
}
运行结果:
1 3 2 5 5 7 8 9 10 11
这段代码依次完成了:
原始数据:1 2
插入 3:1 3 2
插入两个 5:1 3 2 5 5
插入 array:1 3 2 5 5 7 8 9
插入初始化列表:1 3 2 5 5 7 8 9 10 11
六、insert() 的返回值
vector::insert() 通常会返回一个迭代器,这个迭代器指向新插入的第一个元素。
示例代码:
#include <iostream>
#include <vector>
using namespace std;
int main() {
vector<int> v = {1, 2, 3};
auto it = v.insert(v.begin() + 1, 100);
cout << "新插入的元素是:" << *it << endl;
return 0;
}
运行结果:
新插入的元素是:100
这个返回值在实际开发中非常有用,因为它可以帮助我们继续操作刚刚插入的元素。
七、insert() 和 push_back() 的区别
很多初学者容易把 insert() 和 push_back() 混淆。
它们的区别如下:
| 函数 | 作用 | 插入位置 |
|---|---|---|
push_back() |
在容器末尾添加一个元素 | 只能在末尾 |
insert() |
在指定位置插入元素 | 可以在任意位置 |
示例:
vector<int> v = {1, 2, 3};
v.push_back(4);
结果:
1 2 3 4
而:
v.insert(v.begin(), 0);
结果:
0 1 2 3 4
所以可以简单理解为:
push_back() 只能往最后插。
insert() 可以往指定位置插。
八、insert() 和 emplace() 的区别
在 C++11 之后,vector 中还提供了 emplace() 函数。
insert() 和 emplace() 都可以在指定位置插入元素,但是它们的实现思想不同。
insert() 通常是先创建对象,再把对象拷贝或移动到容器中。
emplace() 则是在容器指定位置直接构造对象。
示例代码:
#include <iostream>
#include <vector>
using namespace std;
class Student {
public:
Student(string name, int age) {
cout << "调用构造函数" << endl;
this->name = name;
this->age = age;
}
Student(const Student& s) {
cout << "调用拷贝构造函数" << endl;
this->name = s.name;
this->age = s.age;
}
private:
string name;
int age;
};
int main() {
vector<Student> v;
cout << "使用 insert:" << endl;
v.insert(v.begin(), Student("张三", 18));
cout << "使用 emplace:" << endl;
v.emplace(v.begin(), "李四", 20);
return 0;
}
通常情况下,emplace() 可以减少临时对象的创建,在插入自定义对象时更有优势。参考页中也指出,emplace() 会在容器指定位置直接构造元素,而不是先生成对象再复制或移动到容器中。(C语言中文网)
不过对于 int、char 这类简单类型,insert() 和 emplace() 的性能差距通常并不明显。
九、string 中 insert() 的用法
string 也提供了 insert() 函数,可以在指定位置插入字符或字符串。
1. 在指定下标插入字符串
#include <iostream>
#include <string>
using namespace std;
int main() {
string s = "Hello World";
s.insert(5, " C++");
cout << s << endl;
return 0;
}
运行结果:
Hello C++ World
代码分析:
原字符串:
Hello World
下标 5 的位置在 Hello 后面。
插入 " C++" 后,结果变成:
Hello C++ World
2. 插入多个相同字符
#include <iostream>
#include <string>
using namespace std;
int main() {
string s = "abc";
s.insert(1, 3, 'x');
cout << s << endl;
return 0;
}
运行结果:
axxxbc
代码分析:
在下标 1 的位置,也就是字符 b 前面,插入三个 'x'。
所以结果为:
a x x x b c
std::string::insert() 支持在指定下标位置插入字符、字符串或一段字符区间,cppreference 中也将其描述为向字符串中插入字符的成员函数。(CPP参考)
十、set 中 insert() 的用法
set 是集合容器,它有两个重要特点:
-
元素自动排序。
-
元素不能重复。
所以 set::insert() 插入元素时,如果元素已经存在,就不会重复插入。
示例代码:
#include <iostream>
#include <set>
using namespace std;
int main() {
set<int> s;
s.insert(3);
s.insert(1);
s.insert(2);
s.insert(2);
for (int x : s) {
cout << x << " ";
}
return 0;
}
运行结果:
1 2 3
代码分析:
虽然代码中插入了两次 2,但 set 不允许重复元素,所以最终只保留一个 2。
std::set::insert() 的作用是向集合中插入元素,如果集合中已经存在等价元素,则不会重复插入。(CPP参考)
十一、map 中 insert() 的用法
map 是键值对容器,存储的是:
key-value
也就是:
键 - 值
例如:
姓名 - 分数
学号 - 姓名
编号 - 商品
map 中的 key 不能重复。
示例代码:
#include <iostream>
#include <map>
using namespace std;
int main() {
map<string, int> score;
score.insert({"张三", 90});
score.insert({"李四", 85});
score.insert({"王五", 95});
for (auto item : score) {
cout << item.first << " " << item.second << endl;
}
return 0;
}
运行结果:
张三 90
李四 85
王五 95
其中:
item.first
表示 key。
item.second
表示 value。
map 插入重复 key 的情况
#include <iostream>
#include <map>
using namespace std;
int main() {
map<string, int> score;
score.insert({"张三", 90});
score.insert({"张三", 100});
cout << score["张三"] << endl;
return 0;
}
运行结果:
90
代码分析:
第一次插入:
{"张三", 90}
成功。
第二次插入:
{"张三", 100}
由于 张三 这个 key 已经存在,所以 insert() 不会覆盖原来的值。
如果想覆盖原来的值,可以使用:
score["张三"] = 100;
或者使用 C++17 的:
score.insert_or_assign("张三", 100);
std::map::insert() 在插入键值对时,如果容器中已经存在等价 key,则不会插入新的元素。(CPP参考)
十二、insert() 使用时的注意事项
1. vector 插入位置必须合法
例如:
v.insert(v.begin() + 10, 100);
如果 vector 中根本没有这么多元素,就可能导致程序出现错误。
正确做法是保证插入位置在:
[v.begin(), v.end()]
范围内。
2. vector 中间插入效率较低
vector 的底层是连续空间。
如果在中间插入元素,后面的元素需要整体向后移动。
例如:
vector<int> v = {1, 2, 3, 4, 5};
v.insert(v.begin(), 0);
这行代码会把原来的 1 2 3 4 5 整体往后移动,再把 0 放到最前面。
所以对于 vector 来说:
尾部插入效率较高。
中间或头部插入效率较低。
如果需要频繁在中间插入元素,可以考虑使用 list。
3. vector 插入后迭代器可能失效
vector 在插入元素时,如果容量不够,可能会重新申请一块更大的内存空间。
一旦发生扩容,原来的迭代器、指针、引用都可能失效。
错误示例:
vector<int> v = {1, 2, 3};
auto it = v.begin();
v.insert(v.begin(), 100);
cout << *it << endl;
这段代码有风险,因为插入之后 it 可能已经失效。
更安全的写法是使用 insert() 的返回值:
auto it = v.insert(v.begin(), 100);
cout << *it << endl;
4. set 和 map 的 insert 不一定真的插入成功
对于 set 和 map 来说,由于 key 不能重复,所以插入操作可能失败。
可以通过返回值判断是否插入成功。
示例:
#include <iostream>
#include <set>
using namespace std;
int main() {
set<int> s;
auto result1 = s.insert(10);
auto result2 = s.insert(10);
cout << result1.second << endl;
cout << result2.second << endl;
return 0;
}
运行结果:
1
0
说明:
result.second == true
表示插入成功。
result.second == false
表示插入失败,通常是因为元素已经存在。
十三、常见容器 insert() 对比总结
| 容器 | insert() 作用 | 是否允许重复 | 是否自动排序 |
|---|---|---|---|
vector |
在指定位置插入元素 | 允许 | 不自动排序 |
string |
在指定位置插入字符或字符串 | 允许 | 不自动排序 |
list |
在指定位置插入元素 | 允许 | 不自动排序 |
set |
插入元素 | 不允许 | 自动排序 |
map |
插入键值对 | key 不允许重复 | 按 key 自动排序 |
unordered_set |
插入元素 | 不允许 | 不排序 |
unordered_map |
插入键值对 | key 不允许重复 | 不排序 |
十四、完整练习代码
下面给出一个综合案例,演示 vector、string、set、map 中 insert() 的用法。
#include <iostream>
#include <vector>
#include <string>
#include <set>
#include <map>
using namespace std;
int main() {
// vector 的 insert
vector<int> v = {1, 2, 3};
v.insert(v.begin() + 1, 100);
cout << "vector 插入结果:";
for (int x : v) {
cout << x << " ";
}
cout << endl;
// string 的 insert
string str = "Hello World";
str.insert(5, " C++");
cout << "string 插入结果:" << str << endl;
// set 的 insert
set<int> s;
s.insert(3);
s.insert(1);
s.insert(2);
s.insert(2);
cout << "set 插入结果:";
for (int x : s) {
cout << x << " ";
}
cout << endl;
// map 的 insert
map<string, int> score;
score.insert({"张三", 90});
score.insert({"李四", 85});
score.insert({"张三", 100});
cout << "map 插入结果:" << endl;
for (auto item : score) {
cout << item.first << " " << item.second << endl;
}
return 0;
}
运行结果:
vector 插入结果:1 100 2 3
string 插入结果:Hello C++ World
set 插入结果:1 2 3
map 插入结果:
张三 90
李四 85
十五、总结
本文主要介绍了 C++ STL 中 insert() 函数的常见用法。
对于 vector 来说,insert() 可以在指定位置插入单个元素、多个相同元素、另一个容器的一段元素,也可以插入初始化列表。
对于 string 来说,insert() 可以在指定下标位置插入字符或字符串。
对于 set 来说,insert() 会按照集合规则插入元素,重复元素不会被插入。
对于 map 来说,insert() 用于插入键值对,如果 key 已经存在,则不会覆盖原来的 value。
简单来说:
vector insert:按位置插入
string insert:按下标插入
set insert:按集合规则插入
map insert:按 key-value 插入
掌握 insert() 之后,我们在处理 STL 容器时就可以更加灵活地添加数据,尤其是在刷题、工程开发和数据结构练习中都会经常用到。
更多推荐

所有评论(0)