Effective STL:杂记(一)

2023-05-16

1. 避免使用vector<bool>

    vector<bool>实际上并不能算是一个STL容器,实际上也并不存储bool。因为一个对象要成为STL容器,就必须满足C++标准的第23.1节列出的所有条件,其中一个条件是,如果 c 是包含对象T的容器,而且 c 支持operator[],则必须能够编译下面代码:

T *p = &c[0];

    也就是说容器中应该是存储对象 T,这样子 operator[] 才能返回容器中实际存储的对象,你也可以通过取它的地址得到一个指向该对象的指针。(这里需要假定 T 没有用非常规的方式对 operator & 做重载。)但是对于vector<bool>,底层是用类似于位图的方式存储的。

    对于vector<bool>的operator[],返回的是一个代理对象(proxy project),这个对象表现得像是一个指向单位的引用。为这个代理对象添加一个隐式转向bool的函数就可以让 operator[] 返回一个bool值。所以对于 operator[] 返回值做 operator&,得到的并不是一个bool指针,所以将其赋给bool指针显然是编译不过的。

#include <iostream>
#include <map
#include <vector>

using namespace std;

int main() {
	vector<bool> vb;
	vb.push_back(false);
	vb.push_back(true);
	vb.push_back(false);
	// bool *pb = &vb[0];
	bool pb1 = vb[1];
	cout << pb1 << endl;
	cout << *vb.begin() << endl;
	return 0;
}

    上面的代码输出分别为1和0。但是如果去掉被注释语句的注释符号,则编译是无法通过的。这里vb[1]和*vb.begin()能正常工作应该是对返回值进行了特殊处理。详细的情况需要分析源代码了。

    可以替代vector<bool>的有deque<bool>和bitset,deque<bool>就的确是存储bool的,bitset不是STL容器,是标准C++库的一部分,但是它的大小在编译时就确定了。

2. swap技巧除去多余的容量

    我们知道,随着vector元素的增加,存在一个翻倍扩容的操作,此时会导致vector的长度越来越大,即使我们调用pop_back将元素弹出,其容量也不会变小。最终我们可能需要用resize操作来减少容量。比起resize操作,我们可以用更简单的方式来除去多余的容量,那就是用swap函数来交换两个vector的内容。

#include <iostream>
#include <vector>

using namespace std;

int main() {
	vector<int> vi;
	for (int i = 0; i < 10; ++i) 
		vi.push_back(i);
	vi.pop_back();
	cout << vi.capacity() << endl;        // 输出 16
	vector<int>(vi).swap(vi);
	cout << vi.capacity() << endl;        // 输出 9
	return 0;
}

     上面的代码分别输出 16 和 9。最主要的语句是“vector<int>(vi).swap(vi)”,这里用 vi 的内容来初始化一个临时vector<int>临时变量,则该临时变量将只含有 vi 中实际存在的元素,没有被设置的容量内容并不会被赋值过去,即该临时变量只含有 9 个元素。然后再将其与 vi 交换内容,这个时候 vi 中便仅有9个元素了,不存在多出来的容量。

3. map中operater[]与insert

     map::operator[] 的设计目的是为了提供“添加和更新”(add or update)的功能。operator[] 会返回一个引用,它指向与 k 相关联的值对象。然后 v 被赋给该引用(operator[] 返回那个引用)所指向的对象。如果键 k 已经有了先关联的值,则该值被更新,但问题在于如果 k 还没有在映射表中,它会使用值类型的默认构造函数创建一个新的对象,然后 operator[] 就能返回一个指向该新对象的引用了。

     也就是说,如果键 k 对应的 v 不存在,operator[] 会导致新的对象被创建,不管有没有新的 v 被赋给。

#include <iostream>
#include <map>

using namespace std;

int main() {
	map<int, int> m;
	cout << m.size() << endl;   // 输出:0
	m[10];
	cout << m.size() << endl;   // 输出:1
	if (m.find(10) != m.end()) {
		cout << "has 10" << endl;   // 输出:has 10
	}
	return 0;
}

      通过上面的输出,可以看到虽然在执行了 m[10] 后,m 中新增了一个对象。

      而对于 operator[] 与 insert ,《Effective STL》中讲到对于新增对象,insert函数的效率要高,而更新操作,则是 operator[] 效率要高。书中有讲到一些例子,还没完全消化好,所以直接不分析了。

     通过上面的例子,我们也可以知道不能通过 operator[] 去判断某个键是否存在对应的值,而是应该用 find 函数来判断。 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Effective STL:杂记(一) 的相关文章

随机推荐

  • Mac上Golang语言环境搭建

    文章目录 官网其他参考安装golang源码安装安装包安装使用homebrew安装 配置GOROOTGOPATHGOPROXYGOPRIVATEGONOSUMDB 安装测试 官网 目前无法在家里的直接访问golang org网站 xff1a
  • [已解决] Mac上docker安装prometheus报错:Are you trying to mount a directory onto a file (or vice-versa)?

    文章目录 项目场景问题描述原因分析解决方案 项目场景 Mac上通过docker安装prometheus 问题描述 docker run时 xff0c 会出现下面的报错 xff0c 导致容器启动失败 xff1a docker Error re
  • Mac上安装Node Exporter

    文章目录 安装Node Exporter方法一 xff1a 手动安装方法二 xff1a docker安装 运行测试 node exporter 可以采集机器 xff08 物理机 虚拟机 云主机等 xff09 的监控指标数据 xff0c 能够
  • Docker安装Grafana

    文章目录 Grafana介绍拉取镜像准备相关挂载目录及文件启动容器访问测试添加 Prometheus 数据源常见问题 看板配置 Grafana介绍 上篇博客介绍了prometheus的安装 xff1a Docker部署Prometheus
  • Springboot应用接入Prometheus监控

    文章目录 接入介绍操作步骤修改应用的依赖及配置步骤1 xff1a 修改 pom 依赖步骤2 xff1a 修改配置 本地验证prometheus配置 接入介绍 在使用 Spring Boot 作为开发框架时 xff0c 需要监控应用的状态 x
  • Spring Boot自带监控组件—Actuator介绍

    文章目录 Actuator介绍启用与暴露的区别Spring Boot集成Actuator应用监控框架Actuator监控端点启用端点端点的默认暴露规则案例 自定义端点 Actuator介绍 Actuator是Spring Boot提供的应用
  • Git Commit提交规范总结

    文章目录 前言git commit 提交规范提交消息头 commit message header 提交消息具体内容 commit message body 提交消息尾述 commit message footer Revert 表情 Em
  • 常用kubectl命令总结

    文章目录 配置kubeconfig帮助信息命令查看具体某一个命令的帮助信息列出全局的选项参数 xff08 适用所有的命令 xff09 显示合并的 kubeconfig 配置或一个指定的 kubeconfig 文件 基本命令罗列所支持的完整资
  • 解决:org.apache.catalina.connector.ClientAbortException: java.io.IOException: 断开的管道

    文章目录 项目场景问题描述原因分析解决方案 项目场景 jdk11 Spring Boot 2 x 项目 xff0c Tomcat容器 Nginx 问题描述 系统日志中 xff0c 时不时会出现下面的异常信息 xff1a org apache
  • 解决:No converter for [xxxx] with preset Content-Type ‘text/plain;version=0.0.4;charset=utf-8‘

    文章目录 项目背景问题描述问题分析解决方案方案一 xff1a 修改Controller定义方案二 xff1a 修改Controller返回值方案三 xff1a 全局处理 项目背景 Spring Boot 2 X 问题描述 错误信息如下 xf
  • SYD8821 串口模块使用说明【串口0中断要屏蔽底层调用】

    SYD8821是具有全球领先低功耗 RX 2 4mA 64 94 5dBm灵敏度 xff0c TX 4 3mA 64 0dBm输出功率 的蓝牙低功耗SOC芯片 xff0c 在极低电流下实现了优异的射频性能 xff0c 搭配176kB SRA
  • MySQL的information_schema库下的常用sql

    文章目录 information schema TABLES查看该数据库实例下所有库大小 MB为单位 查看该实例下各个库大小 MB为单位 查看表大小 MB为单位 熟练使用 information schema库里的表 显示在库里的表 xff
  • shell脚本批量转文件格式:dos2unix

    文章目录 可以使用shell脚本实现 xff1a span class token shebang important bin sh span span class token assign left variable dir span s
  • 解决:com.atomikos.icatch.SysException: Error in init: Log already in use? tmlog in ./

    文章目录 项目场景问题描述原因分析详细分析 解决方案 项目场景 Spring Boot 2 x xff0c 集成 atomikos 问题描述 今天在同一个环境启动两个项目时报错 xff0c 因为两个项目同时涉及到分布式事物和切换数据源相关
  • Nginx日志介绍

    文章目录 access log日志流量统计 access log 日志文件一般存放在 var log nginx 下 xff0c 可以使用 tail f命令查看access日志 span class token function tail
  • JVM (Micrometer)-4701面板参数介绍

    文章目录 Quick Facts 概览 堆和非堆内存有以下几个概念 I O Overview xff08 服务黄金指标 xff09 JVM Memory xff08 JVM内存 xff09 JVM Misc xff08 JVM负载 xff0
  • curl文件传输命令

    CURL curl transfer a URL curl 是一个利用URL语法在命令行下工作的文件传输工具 支持文件上传和下载 格式 curl options URLs URL xff1a 通过大括号指定多个url 示例 xff1a cu
  • RS-485信号解析

    这次来看看RS 485信号 使用绿联的USB转RS485模块 线用的颜色不对 xff0c 类型也不对 xff0c 实际使用中请用带屏蔽层的双绞线 示波器CH1是R xff08 B xff09 示波器CH2是R 43 xff08 A xff0
  • T t与T t = T()的区别

    主要的区别就是默认构造函数对内置类型的初始化上 如果没有T中没有定义构造函数 xff0c 则对于 T t xff0c 并不会对 t 中内置类型设置初始值 xff0c 是一个随机值 但对于 T t 61 T xff0c 对 t 中内置类型会设
  • Effective STL:杂记(一)

    1 避免使用vector lt bool gt vector lt bool gt 实际上并不能算是一个STL容器 xff0c 实际上也并不存储bool 因为一个对象要成为STL容器 xff0c 就必须满足C 43 43 标准的第23 1节