[译][译]C++17,容器的持续改进与统一访问

栏目: C++ · 发布时间: 6年前

内容简介:看到一个介绍 C++17 的系列博文(本篇是系列译文的最后一篇(译文总数不到十来篇)~C++11 中已经包含了8个关联容器,C++17 改进了这些容器的接口方法,现在你可以更加方便的向容器中插入元素,合并或者移动一个容器的元素至另一个"

看到一个介绍 C++17 的系列博文( 原文 ),有十来篇的样子,觉得挺好,看看有时间能不能都简单翻译一下,这是第八篇~

本篇是系列译文的最后一篇(译文总数不到十来篇)~

C++11 中已经包含了8个关联容器,C++17 改进了这些容器的接口方法,现在你可以更加方便的向容器中插入元素,合并或者移动一个容器的元素至另一个" 相似 "容器中,并且新标准还统一了关联容器和顺序容器的访问方式.

在我深入讲解细节之前,让我先来回答一下之前的一个问题:什么是"相似"容器?

目前标准库包含8个关联容器:

[译][译]C++17,容器的持续改进与统一访问

所谓的相似容器,其实就是所含元素的数据结构相同并且 数据类型也相同的容器.std::set 和 std::multiset 的元素便拥有相同的数据结构, std::unordered_set 和 std::unordered_multiset, std::map 和 std::multimap, 以及 std::unordered_map 和 std::unordered_multimap, 这几个容器对包含的元素也拥有相同的数据结构.

当然,上面的说明还是比较简略的,更多的细节我在之前的 文章 中已经做过介绍,有兴趣的朋友可以看看.

现在让我们来看些全新的东西.

The improved interface of the associative containers

下面的代码示例较详尽的展示了改进的容器接口.

#include <iostream>
#include <map>
#include <string>
#include <utility>

using namespace std::literals;                                     // 1

template <typename Cont>
void printContainer(const Cont& cont, const std::string& mess) {    // 2
	std::cout << mess;
	for (const auto& pa : cont) {
		std::cout << "(" << pa.first << ": " << pa.second << ") ";
	}
	std::cout << std::endl;
}

int main() {
	std::map<int, std::string> ordMap{ {1, "a"s}, {2, "b"} };          // 3
	ordMap.try_emplace(3, 3, 'C');
	ordMap.try_emplace(3, 3, 'c');

	printContainer(ordMap, "try_emplace: ");

	std::cout << std::endl;

	std::map<int, std::string> ordMap2{ {3, std::string(3, 'C')},     // 4
										{4, std::string(3, 'D')} };
	ordMap2.insert_or_assign(5, std::string(3, 'e'));
	ordMap2.insert_or_assign(5, std::string(3, 'E'));

	printContainer(ordMap2, "insert_or_assign: ");                   // 5

	std::cout << std::endl;

	ordMap.merge(ordMap2);                                           // 6

	std::cout << "ordMap.merge(ordMap2)" << std::endl;

	printContainer(ordMap, "  ordMap: ");
	printContainer(ordMap2, "  ordMap2: ");

	std::cout << std::endl;

	std::cout << "extract and insert: " << std::endl;

	std::multimap<int, std::string> multiMap{ {2017, std::string(3, 'F')} };

	auto nodeHandle = multiMap.extract(2017);                        // 7
	nodeHandle.key() = 6;
	ordMap.insert(std::move(nodeHandle));

	printContainer(ordMap, "   ordMap: ");
	printContainer(multiMap, "   multiMap: ");
	
	return 0;
}

代码示例中我使用了 std::map, 因为多数情况下他都是我们使用关联容器的第一选择.另外,如果你需要存储大量元素并且保证访问效率,你就可以试试 std::unordered_map.在我之前的 文章 中,我对这两个容器的访问效率做了一些比较.

代码 (2) 处我编写了 printContainer 函数用来方便的输出关联容器的元素(可以附加一个消息标题),同样是为了方便,我在 (1) 处引入了命名空间 std::literals,这样我就可以使用 C++ string 中新的内建字面量(literal)了.代码 (3) 中定义的键值对 {1, "a"s} 便是 string 字面量的一个应用: "a"s 是 C++14 引入的 string 字面量定义方式,你只需要在 C 风格字符串后面添加一个 s 字符便可获得一个 C++ string(字面量).

现在,我要开始详细解释示例程序的代码了,为了理解方便,让我们先看下程序的输出:

[译][译]C++17,容器的持续改进与统一访问

新标准中增加了两种向关联容器中添加元素的方法: try_emplace 和 insert_or_assign.代码 (3) 处的 ordMap.try_emplace(3, 3, ‘C’) 尝试向 ordMap 添加一个元素,其中第一个参数 3 是元素的键, 后面的两个参数 3 和 ‘C’ 则直接用于调用元素值(这里是std::string)的构造函数.之所以这个方法以try为前缀命名,是因为如果对应的元素键已经存在,该方法便不会执行实际的添加操作.代码 (4) 处的 insert_or_assign 方法则与 try_emplace 不同,如果对应的元素键已经存在,他会将新的元素值赋值给已经存在的元素键(建立新的键值对映射).

C++17 中,你还可以合并关联容器.代码 (6) 处的 ordMap.merge(ordMap2) 将 ordMap2 合并入了 ordMap 中.这个过程的正式名称叫"拼接(splice)",以上面代码为例,拼接的过程就是从 ordMap2 中抽取(extract)每一个键值对并插入 ordMap 中,如果 ordMap 中已经存在相同的元素键,则不会执行插入操作.整个过程不会发生键值对的 copy 或者 move 操作,所以拼接之前指向键值对的指针(或者引用)仍然保持有效.你可以在相似的关联容器间执行合并操作,而所谓的相似容器,正如之前所说,就是容器所包含的元素拥有相同的数据结构和相同的数据类型.

代码 (7) 处继续进行容器的抽取和插入操作.新标准中的关联容器都有一个新的子类型:node_type,代码 (6) 中的容器合并操作内部就是通过使用 node_type 来完成的.你甚至可以使用 node_type 来改变一个键值对的键:代码 (7) 处的 auto nodeHandle multiMap.extract(2017) 从 std::multimap<int, std::string> 中抽取了键为 2017 的节点(node_type),接下来的代码 nodeHandle.key() = 6 将节点的键改为了 6, 然后使用 ordMap.insert(std::move(nodeHandle)) 将节点插入到了 ordMap 中,这里我必须使用 move 的方式来插入提取的节点,因为 node_type 并不支持拷贝.

当然,你也可以更改抽取节点的键后插入回同一个关联容器中(A),或者直接不做任何更改(B).除了更改键,你也可以更改节点的值©.

auto nodeHandle = multiMap.extract(2017);   // A                      
nodeHandle.key() = 6;
multiMap.insert(std::move(nodeHandle));
  

auto nodeHandle = multiMap.extract(2017);   // B                     
ordMap.insert(std::move(nodeHandle)); 


auto nodeHandle = multiMap.extract(2017);   // C
nodeHandle.mapped() = std::string("ZZZ");
ordMap.insert(std::move(nodeHandle));

C++17 中引入了3个全局函数用以统一的访问容器.

Uniform container access

这3个函数分别是 std::size, std::empty, 和 std::data.

  • std::size: 返回一个 STL 容器,或者一个 C++ string, 或者一个 C 数组的大小(size).
  • std::empty: 返回一个 STL 容器,或者一个 C++ string, 或者一个 C 数组是否为空.
  • std::data: 返回容器所包含元素的内存块指针.使用前提是容器必须支持 data() 方法(标准库中的 std::vector, std::string 和 std::array 支持该方法).

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

商战

商战

杰克•特劳特、阿尔•里斯 / 李正栓、李腾 / 机械工业出版社 / 2011-3 / 42.00元

本书重点阐述了商战中的四种常用战略形式,如防御战、进攻战、侧翼战和游击战,针对每一种形式又提出了三条应遵循的原则,以及如何在具体的商战中应用这些原则。本书分析了商战中的实际案例:可口可乐与百事可乐的战役,汉堡王与温迪斯对麦当劳的挑战以及DEC对阵IBM等。这些人们熟知品牌的案例在作者精心的组织下,使读者不仅加深了对本书中心思想的理解,而且学习了如何在实战中具体应用各种营销战略和策略的技巧。 ......一起来看看 《商战》 这本书的介绍吧!

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具