一、前言

在 C++ STL 中,insert() 是一个非常常见的成员函数,主要用于向容器中插入元素。不同容器中的 insert() 用法不完全相同,例如 vector 可以在指定位置插入元素,string 可以在指定下标插入字符串,setmap 则会按照自身规则插入数据。

本文将从最常见的 vector::insert() 入手,再扩展到 stringsetmap 等常见容器,帮助大家系统掌握 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() 完整示例

下面用一个完整程序演示 vectorinsert() 的多种用法。

#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语言中文网)

不过对于 intchar 这类简单类型,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 是集合容器,它有两个重要特点:

  1. 元素自动排序。

  2. 元素不能重复。

所以 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 不一定真的插入成功

对于 setmap 来说,由于 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 不允许重复 不排序

十四、完整练习代码

下面给出一个综合案例,演示 vectorstringsetmapinsert() 的用法。

#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 容器时就可以更加灵活地添加数据,尤其是在刷题、工程开发和数据结构练习中都会经常用到。

更多推荐