ACM-C++STL部分函数及其用法

本文最后更新于:December 3, 2021 pm

记录STL提供的有关容器的函数及其用法。此片博客内容较多,篇幅较长。

目录

一.vector 添加元素的两种函数

push_back()函数

该成员函数的功能是在 vector 容器 尾部 添加一个元素,用法也非常简单。简单举例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector<int> values{};
values.push_back(1);
values.push_back(2);
for (int i = 0; i < values.size(); i++) {
cout << values[i] << " ";
}
return 0;
}
//输出结果
1 2

emplace_back()函数

该函数是 C++ 11 新增加的,其功能和 push_back() 相同,都是在 vector 容器的尾部添加一个元素。简单例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector<int> values{};
values.emplace_back(1);
values.emplace_back(2);
for (int i = 0; i < values.size(); i++) {
cout << values[i] << " ";
}
return 0;
}
//输出结果
1 2

以上 2 段代码,只是用 emplace_back() 替换了 push_back(),它们实现的功能是一样的。

那么 C++ 11 标准中为什么要多此一举呢?
在于他们还是有一定的区别。

区别

emplace_back() 和 push_back() 的区别,就在于底层实现的机制不同。push_back() 向容器尾部添加元素时,首先会创建这个元素,然后再将这个元素拷贝或者移动到容器中(如果是拷贝的话,事后会自行销毁先前创建的这个元素);而 emplace_back() 在实现时,则是直接在容器尾部创建这个元素,省去了拷贝或移动元素的过程。

用例子了解它们之间的区别:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include <vector> 
#include <iostream>
using namespace std;
class testDemo
{
public:
testDemo(int num):num(num){
std::cout << "调用构造函数" << endl;
}
testDemo(const testDemo& other) :num(other.num) {
std::cout << "调用拷贝构造函数" << endl;
}
testDemo(testDemo&& other) :num(other.num) {
std::cout << "调用移动构造函数" << endl;
}
private:
int num;
};
int main()
{
cout << "emplace_back:" << endl;
std::vector<testDemo> demo1;
demo1.emplace_back(2);
cout << "push_back:" << endl;
std::vector<testDemo> demo2;
demo2.push_back(2);
}
//输出结果
emplace_back:
调用构造函数
push_back:
调用构造函数
调用移动构造函数

//若将 testDemo 类中的移动构造函数注释掉,再运行程序会发现,运行结果变为:
emplace_back:
调用构造函数
push_back:
调用构造函数
调用拷贝构造函数

可以看出,push_back() 在底层实现时,会优先选择调用移动构造函数,如果没有才会调用拷贝构造函数。显然完成同样的操作,push_back() 的底层实现过程比 emplace_back() 更繁琐,换句话说,emplace_back() 的执行效率比 push_back() 高。因此,在实际使用时,建议还是优先选用 emplace_back()。

由于 emplace_back() 是 C++ 11 标准新增加的,如果程序要兼顾之前的版本,还是应该使用 push_back()。


二.vector 插入元素的两种函数

vector容器提供了 insert() 和 emplace() 这 2 个成员函数,用来实现在容器指定位置处插入元素。

insert()函数

insert() 函数的功能是在 vector 容器的指定位置插入一个或多个元素。该函数的语法格式有多种.

语法格式 用法说明
iterator insert(pos,elem) 在迭代器 pos 指定的位置之前插入一个新元素elem,并返回表示新插入元素位置的迭代器。
iterator insert(pos,n,elem) 在迭代器 pos 指定的位置之前插入 n 个元素 elem,并返回表示第一个新插入元素位置的迭代器。
iterator insert(pos,first,last) 在迭代器 pos 指定的位置之前,插入其他容器(不仅限于vector)中位于 [first,last) 区域的所有元素,并返回表示第一个新插入元素位置的迭代器。
iterator insert(pos,initlist) 在迭代器 pos 指定的位置之前,插入初始化列表(用大括号{}括起来的多个元素,中间有逗号隔开)中所有的元素,并返回表示第一个新插入元素位置的迭代器。

演示使用 insert() 函数向 vector 容器中插入元素:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <iostream> 
#include <vector>
#include <array>
using namespace std;
int main()
{
std::vector<int> demo{1,2};
//第一种格式用法
demo.insert(demo.begin() + 1, 3);//{1,3,2}
//第二种格式用法
demo.insert(demo.end(), 2, 5);//{1,3,2,5,5}
//第三种格式用法
std::array<int,3>test{ 7,8,9 };
demo.insert(demo.end(), test.begin(), test.end());//{1,3,2,5,5,7,8,9}
//第四种格式用法
demo.insert(demo.end(), { 10,11 });//{1,3,2,5,5,7,8,9,10,11}
for (int i = 0; i < demo.size(); i++) {
cout << demo[i] << " ";
}
return 0;
}
//输出结果
1 3 2 5 5 7 8 9 10 11

emplace()函数

emplace() 是 C++ 11 标准新增加的成员函数,用于在 vector 容器指定位置之前插入一个新的元素。emplace() 每次只能插入一个元素,而不是多个。

该函数的语法格式:

1
iterator emplace (const_iterator pos, args...);

其中,pos 为指定插入位置的迭代器;args… 表示与新插入元素的构造函数相对应的多个参数;该函数会返回表示新插入元素位置的迭代器。
简单的理解 args…,即被插入元素的构造函数需要多少个参数,那么在 emplace() 的第一个参数的后面,就需要传入相应数量的参数。

例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <vector>
#include <iostream>
using namespace std;
int main()
{
std::vector<int> demo1{1,2};
//emplace() 每次只能插入一个 int 类型元素
demo1.emplace(demo1.begin(), 3);
for (int i = 0; i < demo1.size(); i++) {
cout << demo1[i] << " ";
}
return 0;
}
//输出结果
3 1 2

既然 emplace() 和 insert() 都能完成向 vector 容器中插入新元素,那么谁的运行效率更高呢?
答案是 emplace()。

区别代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include <vector>
#include <iostream>
using namespace std;
class testDemo
{
public:
testDemo(int num) :num(num) {
std::cout << "调用构造函数" << endl;
}
testDemo(const testDemo& other) :num(other.num) {
std::cout << "调用拷贝构造函数" << endl;
}
testDemo(testDemo&& other) :num(other.num) {
std::cout << "调用移动构造函数" << endl;
}
testDemo& operator=(const testDemo& other);
private:
int num;
};
testDemo& testDemo::operator=(const testDemo& other) {
this->num = other.num;
return *this;
}
int main()
{
cout << "insert:" << endl;
std::vector<testDemo> demo2{};
demo2.insert(demo2.begin(), testDemo(1));
cout << "emplace:" << endl;
std::vector<testDemo> demo1{};
demo1.emplace(demo1.begin(), 1);
return 0;
}
//输出结果
insert:
调用构造函数
调用移动构造函数
emplace:
调用构造函数

当拷贝构造函数和移动构造函数同时存在时,insert() 会优先调用移动构造函数。
可以看到,通过 insert() 函数向 vector 容器中插入 testDemo 类对象,需要调用类的构造函数和移动构造函数(或拷贝构造函数);而通过 emplace() 函数实现同样的功能,只需要调用构造函数即可。
简单的理解,就是 emplace() 在插入元素时,是在容器的指定位置直接构造元素,而不是先单独生成,再将其复制(或移动)到容器中。因此,在实际使用中,推荐大家优先使用 emplace()。


三.list 添加(插入)元素

list 模板类中,与“添加或插入新元素”相关的成员方法有如下几个:

push_front():向 list 容器首个元素前添加新元素;
push_back():向 list 容器最后一个元素后添加新元素;
emplace_front():在容器首个元素前直接生成新的元素;
emplace_back():在容器最后一个元素后直接生成新的元素;
emplace():在容器的指定位置直接生成新的元素;
insert():在指定位置插入新元素;
splice():将其他 list 容器存储的多个元素添加到当前 list 容器的指定位置处。

以上这些成员方法中,除了 insert() 和 splice() 方法有多种语法格式外,其它成员方法都仅有 1 种语法格式。用法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>
#include <list>
using namespace std;
int main()
{
std::list<int> values{1,2,3};
values.push_front(0);//{0,1,2,3}
values.push_back(4); //{0,1,2,3,4}
values.emplace_front(-1);//{-1,0,1,2,3,4}
values.emplace_back(5); //{-1,0,1,2,3,4,5}

//emplace(pos,value),其中 pos 表示指明位置的迭代器,value为要插入的元素值
values.emplace(values.end(), 6);//{-1,0,1,2,3,4,5,6}
for (auto p = values.begin(); p != values.end(); ++p) {
cout << *p << " ";
}
return 0;
}
//输出结果
-1,0,1,2,3,4,5,6

insert()成员方法

insert() 成员方法的语法格式有 4 种。

语法格式 用法说明
iterator insert(pos,elem) 在迭代器 pos 指定的位置之前插入一个新元素 elem,并返回表示新插入元素位置的迭代器。
iterator insert(pos,n,elem) 在迭代器 pos 指定的位置之前插入 n 个元素 elem,并返回表示第一个新插入元素位置的迭代器。
iterator insert(pos,first,last) 在迭代器 pos 指定的位置之前,插入其他容器(例如 array、vector、deque 等)中位于 [first,last) 区域的所有元素,并返回表示第一个新插入元素位置的迭代器。
iterator insert(pos,initlist) 在迭代器 pos 指定的位置之前,插入初始化列表(用大括号 { } 括起来的多个元素,中间有逗号隔开)中所有的元素,并返回表示第一个新插入元素位置的迭代器。

演示用法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <iostream>
#include <list>
#include <array>
using namespace std;
int main()
{
std::list<int> values{ 1,2 };
//第一种格式用法
values.insert(values.begin() , 3);//{3,1,2}
//第二种格式用法
values.insert(values.end(), 2, 5);//{3,1,2,5,5}
//第三种格式用法
std::array<int, 3>test{ 7,8,9 };
values.insert(values.end(), test.begin(), test.end());//{3,1,2,5,5,7,8,9}
//第四种格式用法
values.insert(values.end(), { 10,11 });//{3,1,2,5,5,7,8,9,10,11}
for (auto p = values.begin(); p != values.end(); ++p)
{
cout << *p << " ";
}
return 0;
}
//输出结果
3 1 2 5 5 7 8 9 10 11

不知道有没有人发现,同样是实现插入元素的功能,无论是 push_front()、push_back() 还是 insert(),都有以 emplace 为名且功能和前者相同的成员函数。这是因为,后者是 C++ 11 标准新添加的,在大多数场景中,都可以完全替代前者实现同样的功能。更重要的是,实现同样的功能,emplace 系列方法的执行效率更高。

splice()成员方法

和 insert() 成员方法相比,splice() 成员方法的作用对象是其它 list 容器,其功能是将其它 list 容器中的元素添加到当前 list 容器中指定位置处。
splice() 成员方法的语法格式有 3 种。

语法格式 功能
void splice (iterator position, list& x); position 为迭代器,用于指明插入位置;x 为另一个 list 容器。 此格式的 splice() 方法的功能是,将 x 容器中存储的所有元素全部移动当前 list 容器中 position 指明的位置处。
void splice (iterator position, list& x, iterator i); position 为迭代器,用于指明插入位置;x 为另一个 list 容器;i 也是一个迭代器,用于指向 x 容器中某个元素。 此格式的 splice() 方法的功能是将 x 容器中 i 指向的元素移动到当前容器中 position 指明的位置处。
void splice (iterator position, list& x, iterator first, iterator last); position 为迭代器,用于指明插入位置;x 为另一个 list 容器;first 和 last 都是迭代器,[fist,last) 用于指定 x 容器中的某个区域。 此格式的 splice() 方法的功能是将 x 容器 [first, last) 范围内所有的元素移动到当前容器 position 指明的位置处。

list 容器底层使用的是链表存储结构,splice() 成员方法移动元素的方式是,将存储该元素的节点从 list 容器底层的链表中摘除,然后再链接到当前 list 容器底层的链表中。这意味着,当使用 splice() 成员方法将 x 容器中的元素添加到当前容器的同时,该元素会从 x 容器中删除。

演示用法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <iostream>
#include <list>
using namespace std;
int main()
{
//创建并初始化 2 个 list 容器
list<int> mylist1{ 1,2,3,4 }, mylist2{10,20,30};
list<int>::iterator it = ++mylist1.begin(); //指向 mylist1 容器中的元素 2

//调用第一种语法格式
mylist1.splice(it, mylist2); // mylist1: 1 10 20 30 2 3 4
// mylist2:
// it 迭代器仍然指向元素 2,只不过容器变为了 mylist1
//调用第二种语法格式,将 it 指向的元素 2 移动到 mylist2.begin() 位置处
mylist2.splice(mylist2.begin(), mylist1, it); // mylist1: 1 10 20 30 3 4
// mylist2: 2
// it 仍然指向元素 2

//调用第三种语法格式,将 [mylist1.begin(),mylist1.end())范围内的元素移动到 mylist.begin() 位置处
mylist2.splice(mylist2.begin(), mylist1, mylist1.begin(), mylist1.end());//mylist1:
//mylist2:1 10 20 30 3 4 2

cout << "mylist1 包含 " << mylist1.size() << "个元素" << endl;
cout << "mylist2 包含 " << mylist2.size() << "个元素" << endl;
//输出 mylist2 容器中存储的数据
cout << "mylist2:";
for (auto iter = mylist2.begin(); iter != mylist2.end(); ++iter) {
cout << *iter << " ";
}
return 0;
}
//输出结果
mylist1 包含 0个元素
mylist2 包含 7个元素
mylist2:1 10 20 30 3 4 2

四.list 删除元素

成员函数 功能
pop_front() 删除位于 list 容器头部的一个元素。
pop_back() 删除位于 list 容器尾部的一个元素。
erase() 该成员函数既可以删除 list 容器中指定位置处的元素,也可以删除容器中某个区域内的多个元素。
clear() 删除 list 容器存储的所有元素。
remove(val) 删除容器中所有等于 val 的元素。
unique() 删除容器中相邻的重复元素,只保留一份。
remove_if() 删除容器中满足条件的元素。

常见函数就只是简单记录一下用法:

1
2
3
4
list<int>values;
values.pop_front();//删除当前容器中首个元素
values.pop_back(); //删除当前容器最后一个元素
values.clear();//清空容器,删除容器中所有的元素

erase() 成员函数有以下 2 种语法格式:

1
2
iterator erase (iterator position);
iterator erase (iterator first, iterator last);

利用第一种语法格式,可实现删除 list 容器中 position 迭代器所指位置处的元素。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <iostream>
#include <list>
using namespace std;
int main()
{
list<int>values{ 1,2,3,4,5 };
//指向元素 1 的迭代器
auto del = values.begin();
//迭代器右移,改为指向元素 2
++del;
values.erase(del); //{1,3,4,5}
for (auto begin = values.begin(); begin != values.end(); ++begin)
{
cout << *begin << " ";
}
return 0;
}
//输出结果
1 3 4 5

利用第二种语法格式,可实现删除 list 容器中 first 迭代器和 last 迭代器限定区域内的所有元素(包括 first 指向的元素,但不包括 last 指向的元素)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>
#include <list>
using namespace std;
int main()
{
list<int>values{ 1,2,3,4,5 };
//指定删除区域的左边界
auto first = values.begin();
++first;//指向元素 2
//指向删除区域的右边界
auto last = values.end();
--last;//指向元素 5
//删除 2、3 和 4
values.erase(first, last);
for (auto begin = values.begin(); begin != values.end(); ++begin)
{
cout << *begin << " ";
}
return 0;
}
//输出结果
1 5

erase() 成员函数是按照被删除元素所在的位置来执行删除操作,如果想根据元素的值来执行删除操作,可以使用 remove() 成员函数。例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <iostream>
#include <list>
using namespace std;
int main()
{
list<char>values{'a','b','c','d'};
values.remove('c');
for (auto begin = values.begin(); begin != values.end(); ++begin)
{
cout << *begin << " ";
}
return 0;
}
//输出结果
a b d

unique() 函数也有以下 2 种语法格式:

1
2
void unique()
void unique(BinaryPredicate)//传入一个二元谓词函数

以上 2 种格式都能实现去除 list 容器中相邻重复的元素,仅保留一份。但第 2 种格式的优势在于,我们能自定义去重的规则,例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <iostream>
#include <list>
using namespace std;
//二元谓词函数
bool demo(double first, double second)
{
return (int(first) == int(second));
}
int main()
{
list<double> mylist{ 1,1.2,1.2,3,4,4.5,4.6 };
//删除相邻重复的元素,仅保留一份
mylist.unique();//{1, 1.2, 3, 4, 4.5, 4.6}
for (auto it = mylist.begin(); it != mylist.end(); ++it)
cout << *it << ' ';
cout << endl;
//demo 为二元谓词函数,是我们自定义的去重规则
mylist.unique(demo);
for (auto it = mylist.begin(); it != mylist.end(); ++it)
std::cout << *it << ' ';
return 0;
}
//输出结果
1 1.2 3 4 4.5 4.6
1 3 4

注意,除了以上一定谓词函数的方式,还可以使用 lamba表达式以及函数对象的方式定义。
通过调用无参的 unique(),仅能删除相邻重复(也就是相等)的元素,而通过我们自定义去重的规则,可以更好的满足在不同场景下去重的需求。
除此之外,通过将自定义的谓词函数(不限定参数个数)传给 remove_if() 成员函数,list 容器中能使谓词函数成立的元素都会被删除。例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>
#include <list>
using namespace std;
int main()
{
std::list<int> mylist{ 15, 36, 7, 17, 20, 39, 4, 1 };
//删除 mylist 容器中能够使 lamba 表达式成立的所有元素。
mylist.remove_if([](int value) {return (value < 10); }); //{15 36 17 20 39}
for (auto it = mylist.begin(); it != mylist.end(); ++it)
std::cout << ' ' << *it;
return 0;
}
//输出结果
15 36 17 20 39

五.map 容器插入键值的两种函数

map中除了insert()方法可以插入外。C++ STL map 类模板中还提供了 emplace() 和 emplace_hint() 成员函数,也可以实现向 map 容器中插入新的键值对。
实现相同的插入操作,无论是用 emplace() 还是 emplace_hont(),都比 insert() 方法的效率高。

和 insert() 方法相比,emplace() 和 emplace_hint() 方法的使用要简单很多,因为它们各自只有一种语法格式。其中,emplace() 方法的语法格式如下:

1
2
template <class... Args>
pair<iterator,bool> emplace (Args&&... args);

参数 (Args&&… args) 指的是,这里只需要将创建新键值对所需的数据作为参数直接传入即可,此方法可以自行利用这些数据构建出指定的键值对。另外,该方法的返回值也是一个 pair 对象,其中 pair.first 为一个迭代器,pair.second 为一个 bool 类型变量:

  • 当该方法将键值对成功插入到 map 容器中时,其返回的迭代器指向该新插入的键值对,同时 bool 变量的值为 true;
  • 当插入失败时,则表明 map 容器中存在具有相同键的键值对,此时返回的迭代器指向此具有相同键的键值对,同时 bool 变量的值为 false。

emplace() 方法的具体用法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <iostream>
#include <map> //map
#include <string> //string
using namespace std;
int main()
{
//创建并初始化 map 容器
std::map<string, string>mymap;
//插入键值对
pair<map<string, string>::iterator, bool> ret = mymap.emplace("STL教程", "https://lichengloong.com/");
cout << "1、ret.iter = <{" << ret.first->first << ", " << ret.first->second << "}, " << ret.second << ">" << endl;
//插入新键值对
ret = mymap.emplace("C语言教程", "https://lichengloong.com/");
cout << "2、ret.iter = <{" << ret.first->first << ", " << ret.first->second << "}, " << ret.second << ">" << endl;
//失败插入的样例
ret = mymap.emplace("STL教程", "https://lichengloong.com/");
cout << "3、ret.iter = <{" << ret.first->first << ", " << ret.first->second << "}, " << ret.second << ">" << endl;
return 0;
}
//输出结果
1、ret.iter = <{STL教程, https://lichengloong.com/}, 1>
2、ret.iter = <{C语言教程, https://lichengloong.com/}, 1>
3、ret.iter = <{STL教程, https://lichengloong.com/}, 0>

程序中共执行了 3 次向 map 容器插入键值对的操作,其中前 2 次都成功了,第 3 次由于要插入的键值对的键和 map 容器中已存在的键值对的键相同,因此插入失败。

emplace_hint() 方法的功能和 emplace() 类似,其语法格式如下:

1
2
template <class... Args>
iterator emplace_hint (const_iterator position, Args&&... args);

显然和 emplace() 语法格式相比,有以下 2 点不同:

1.该方法不仅要传入创建键值对所需要的数据,还需要传入一个迭代器作为第一个参数,指明要插入的位置(新键值对键会插入到该迭代器指向的键值对的前面);
2.该方法的返回值是一个迭代器,而不再是 pair 对象。当成功插入新键值对时,返回的迭代器指向新插入的键值对;反之,如果插入失败,则表明 map 容器中存有相同键的键值对,返回的迭代器就指向这个键值对。

emplace_hint() 方法的用法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>
#include <map> //map
#include <string> //string
using namespace std;
int main()
{
//创建并初始化 map 容器
std::map<string, string>mymap;
//指定在 map 容器插入键值对
map<string, string>::iterator iter = mymap.emplace_hint(mymap.begin(),"STL教程", "https://lichengloong.com/");
cout << iter->first << " " << iter->second << endl;
iter = mymap.emplace_hint(mymap.begin(), "C语言教程", "https://lichengloong.com/");
cout << iter->first << " " << iter->second << endl;
//插入失败样例
iter = mymap.emplace_hint(mymap.begin(), "STL教程", "https://lichengloong.com/");
cout << iter->first << " " << iter->second << endl;
return 0;
}
//输出结果
STL教程 https://lichengloong.com/
C语言教程 https://lichengloong.com/
STL教程 https://lichengloong.com/

和 insert() 方法一样,虽然 emplace_hint() 方法指定了插入键值对的位置,但 map 容器为了保持存储键值对的有序状态,可能会移动其位置。


六.set 容器添加元素的两种方法

set 类模板提供的所有成员方法中,能实现向指定 set 容器中添加新元素的,只有 3 个成员方法,分别为 insert()、emplace() 和 emplace_hint()。其中 insert() 成员方法的用法比较常规,这里就不再记录具体用法了。

emplace() 和 emplace_hint() 是 C++ 11 标准加入到 set 类模板中的,相比具有同样功能的 insert() 方法,完成同样的任务,emplace() 和 emplace_hint() 的效率会更高。

emplace()函数

emplace() 方法的语法格式:

1
2
template <class... Args>
pair<iterator,bool> emplace (Args&&... args);

其中,参数 (Args&&… args) 指的是,只需要传入构建新元素所需的数据即可,该方法可以自行利用这些数据构建出要添加的元素。比如,若 set 容器中存储的元素类型为自定义的结构体或者类,则在使用 emplace() 方法向容器中添加新元素时,构造新结构体变量(或者类对象)需要多少个数据,就需要为该方法传入相应个数的数据。

该方法的返回值类型为 pair 类型,其包含 2 个元素,一个迭代器和一个 bool 值:

  • 当该方法将目标元素成功添加到 set 容器中时,其返回的迭代器指向新插入的元素,同时 bool 值为 true;
  • 当添加失败时,则表明原 set 容器中已存在相同值的元素,此时返回的迭代器指向容器中具有相同键的这个元素,同时 bool 值为 false。

演示 emplace() 方法的具体用法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <iostream>
#include <set>
#include <string>
using namespace std;
int main(){
//创建并初始化 set 容器
std::set<string>myset;
//向 myset 容器中添加元素
pair<set<string, string>::iterator, bool> ret = myset.emplace("https://lichengloong.com/");
cout << "myset size = " << myset.size() << endl;
cout << "ret.iter = <" << *(ret.first) << ", " << ret.second << ">" << endl;
return 0;
}
//输出结果
myset size = 1
ret.iter = <https://lichengloong.com/, 1>

从执行结果可以看出,通过调用 emplace() 方法,成功向空 myset 容器中添加了一个元素,并且该方法的返回值中就包含指向新添加元素的迭代器。

emplace_hint()函数

emplace_hint() 方法的功能和 emplace() 类似,其语法格式如下:

1
2
template <class... Args>
iterator emplace_hint (const_iterator position, Args&&... args);

和 emplace() 方法相比,有以下 2 点不同:

  • 该方法需要额外传入一个迭代器,用来指明新元素添加到 set 容器的具体位置(新元素会添加到该迭代器指向元素的前面);
  • 返回值是一个迭代器,而不再是 pair 对象。当成功添加元素时,返回的迭代器指向新添加的元素;反之,如果添加失败,则迭代器就指向 set 容器和要添加元素的值相同的元素。

演示 emplace_hint() 方法的用法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <iostream>
#include <set>
#include <string>
using namespace std;
int main(){
//创建并初始化 set 容器
std::set<string>myset;
//在 set 容器的指定位置添加键值对
set<string>::iterator iter = myset.emplace_hint(myset.begin(), "https://lichengloong.com/");
cout << "myset size = " << myset.size() << endl;
cout << *iter << endl;
return 0;
}
//输出结果
myset size = 1
https://lichengloong.com/

需要注意的是,和 insert() 方法一样,虽然 emplace_hint() 方法中指定了添加新元素的位置,但 set 容器为了保持数据的有序状态,可能会移动其位置。

至于比 insert() 执行效率高的原因,可参照 map 容器 emplace() 和 emplace_hint() 比 insert() 效率高的原因,它们是完全一样的。


本文作者: 墨水记忆
本文链接: https://tothefor.com/DragonOne/3459732021.html
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!