C++17新特性之try_emplace与insert_or_assign

175

由于std::map中,元素的key是唯一的,我们经常遇到这样的场景,向map中插入元素时,先检测map指定的key是否存在,不存在时才做插入操作,如果存在,直接取出来使用,或者key不存在时,做插入操作,存在时做更新操作。

通用的做法,可以直接用emplace操作,判断指定的key是否存在,如果不存在,则插入元素,当元素存在的时候,emplace依然会构造一次带待插入元素,判断不需要插入后,将该元素析构,这样导致的后果是,产生了多余的构造和析构操作。

鉴于此,C++17引入了std::try_emplace,在参数列表中,把key和value分开,该方法会检测指定的key是否存在,如果存在,什么也不做,不存在,则插入相应的value。

此外,C++17为map容器还新增了insert_or_assign方法,让我们无需像之前一样,额外编写先判断是否存在,不存在则插入,存在则更新的代码了。

废话不多说,看简单的demo实例代码:

#include "stdafx.h"
#include <iostream>
#include <map>

using namespace std;

void PrintMap(const string& type, const map<string, int>& val)
{
	cout << type << endl;

	for (const auto& [user, age] : val)
	{
		cout << user << ":" << age << endl;
	}
}

int main()
{
	map<string, int> map_user_age = { {"Tom", 10}, {"Jerry", 12}, {"Neo", 13} };

	PrintMap("original map", map_user_age);

	auto [iter_tom, inserted_tom] = map_user_age.try_emplace("Tom", 14);

	PrintMap("insert Tom:14(try_emplace)", map_user_age);

	auto [iter_jim, inserted_jim] = map_user_age.try_emplace("Jim", 14);
	
	PrintMap("insert Jim:14(try_emplace)", map_user_age);

	auto [iter_neo, inserted_neo] = map_user_age.insert_or_assign("Neo", 18);

	PrintMap("insert Neo:18(insert_or_assign)", map_user_age);

	auto [iter_tom_ia, inserted_tom_ia] = map_user_age.insert_or_assign("Tom", 16);

	PrintMap("insert Tom:16(insert_or_assign)", map_user_age);
		
	return 0;
}

猜一猜运行结果:

上述实例代码可以看到:insert_or_assign方法与 try_emplace的不同之处在于,如果对应的key已经存在,使用insert_or_assign会将新的value值赋值给已经存在的key(建立新的键值对映射)。