浅显理解std::vector< bool >

std::vector< bool >因为底层不是直接存储了1字节的bool,而是存储了bit位,通常导致使用方式不当会产生奇奇怪怪的问题,所以总结一下。

std::vector< bool >的源码分析

std::vector<bool>,是类 sd::vector<T,std::allocator<T>> 的部分特化,为了节省内存,内部实际上是按bit来表征bool类型。从底层实现来看,std::vector<bool> 可视为动态的std::bitset,只是接口符合 std::vector,换个名字表达为 DynamicBitset 更为合理。

_Bit_type:std::vecotr<bool>实际存储的底层数据类型的bit大小

在C++标准中,并没有单独的bit类型。

GNU-STL使用一个typedef,将 unsigned long 定义为 _Bit_type,这样一个_Bit_type 就有64bit,也就可以存储64个bool类型变量。

typedef unsigned long _Bit_type;  // _Bit_typeenum{_S_word_bit = int(__CHAR_BIT__ * sizeof(_Bit_type))// 一个 _Bit_type 类型能存储 _S_word_bit 个bit// 注意:在X86-64位CPU上,unsigned long 类型在 MSVC中4个字节(不太符合常规),在GCC中8个字节。};

因此,当 std::vector<bool>要存储__n个bool类型时,底层实际上只需要__n个bit。

那__n个bit对应多少个_Bit_type呢?

static成员函数_S_nword:求需要多少个_Bit_type

在 std::_Bvector_base 类中有个static成员函数 _S_nword ,其返回值就是 __n 个bit所需的 _Bit_type个数。

// std::_Bvector_base 后文分析template <typename _Alloc>size_t _Bvector_base::_S_nword(size_t __n){ return (__n + int(_S_word_bit) - 1) / int(_S_word_bit); }
std::_Bit_reference:实现bool与_Bit_type的映射

怎么将一个bool类型变量映射到_Bit_type中每一个bit,这由类 std::_Bit_reference 实现的。

类 std::_Bit_reference 是 std::vector<bool> 中的基本存储单位。 比如,std::vector<bool>的 operator[]函数返回值类型就是std::_Bit_reference,而不是 bool 类型 。

typedef _Bit_reference reference;reference operator[]( size_type pos );
const_reference operator[]( size_type pos ) const;

使用auto对std::vector<bool>进行推导,获得的是std::_Bit_reference 类型,而不是bool类型。

为了让 operator[] 的返回值能和bool类型变量表现得一致,std::_Bit_reference 就必须满足两点:

  1. std::_Bit_reference能隐式转换为bool类型
  2. 能接受bool类型赋值

在类 std::_Bit_reference 内部有两个字段:

_M_p:_Bit_type*类型,指向的 _Bit_type 类型数据内存
_M_mask:_Bit_type类型,用于指示_M_p的每一位是0还是1,即false 还是 true
通过这两个字段,将一个bool类型变量映射到_M_p上的某个bit。

  struct _Bit_reference{_Bit_type* _M_p;_Bit_type  _M_mask;_Bit_reference(_Bit_type *__x, _Bit_type __y): _M_p(__x), _M_mask(__y) {}_Bit_reference() noexcept : _M_p(0), _M_mask(0) {}_Bit_reference(const _Bit_reference &) = default;// 隐式转成 bool// bool state = vb[1]; 触发的就是此函数operator bool() const noexcept{ return !!(*_M_p & _M_mask); }// 将 _M_p 的 _M_mask 位,设置为 _x 状态// vb[1] = true; 触发的就是此函数_Bit_reference& operator=(bool __x) noexcept{if (__x)*_M_p |= _M_mask;  // 1else*_M_p &= ~_M_mask;return *this;}// 这个函数实际上调用了://   1. 先调用了 operator bool() const noexcept//   2. 在调用了 _Bit_reference& operator=(bool __x) noexcept_Bit_reference& operator=(const _Bit_reference &__x) noexcept{ return *this = bool(__x); }bool operator==(const _Bit_reference &__x) const{ return bool(*this) == bool(__x); }bool operator<(const _Bit_reference &__x) const{ return !bool(*this) && bool(__x); }void flip() noexcept{ *_M_p ^= _M_mask; }};

剩余源码分析见原文。

内存分配总结

std::vector<bool> 的全称是 std::vector<bool, std::allocator<bool>>,最初传入的分配器是std::allocator<bool>,是为bool类型变量分配内存的。

但由STL对bool类型做了特化,内部并不是存储bool类型,而是_Bit_type类型,因此 std::allocator 现在需要为_Bit_type类型分配内存,这就需要通过 rebind 函数来获得 std::allocator<_Bit_type> 。

源码分析总结

获得 _Bit_reference 对象
首先根据__n 定位到具体的第几个_Bit_type对象及其具体的某位,最终返回的是 _Bit_reference类型:

  *iterator(this->_M_impl._M_start._M_p + __n / int(_S_word_bit),__n % int(_S_word_bit));

注意,返回的_Bit_reference 是由如下函数得到的:

  reference std::_Bit_iterator::operator*() const{ return reference(_M_p, 1UL << _M_offset); }

也就是说,返回的_Bit_reference对象的_M_mask字段中, 仅需要改变值的那位是1,其他位置都是0。

给_Bit_reference对象赋值

_Bit_reference& _Bit_reference::operator=(bool __x) noexcept
{if (__x)*_M_p |= _M_mask;  else*_M_p &= ~_M_mask;return *this;
}

此时调用的是_Bit_reference 的operator=函数,仅改变需要改变的那位,对其他bit不会改变。

原文链接: https://leetcode.cn/circle/discuss/dGSFg1/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/150501.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

DVWA -xss

什么是XSS 跨站点脚本(Cross Site Scripting,XSS)是指客户端代码注入攻击&#xff0c;攻击者可以在合法网站或Web应用程序中执行恶意脚本。当wb应用程序在其生成的输出中使用未经验证或未编码的用户输入时&#xff0c;就会发生XSS。 跨站脚本攻击&#xff0c;XSS(Cross Site S…

多线程 - 定时器

多线程 - 定时器 定时器的背景知识 定时器 ~~ (就类似于定闹钟) 平时的闹钟,有两种风格: 指定特定时刻,提醒指定特定时间段之后,提醒 这里的“定时器”,不是提醒,而是执行一个实现准备好的方法/代码,它是开发中一个常用的组件,尤其是在网络编程的时候,使用浏览器上网,打开…

亚马逊计划向开创性的人工智能初创公司Anthropic投资高达4亿美元

原创 | 文 BFT机器人 在一项巨大而突破性的举措中&#xff0c;亚马逊公布了向人工智能初创公司Anthropic投资高达4亿美元的计划&#xff0c;其愿景是创建更易于理解和可控的人工智能系统。此次合作标志着亚马逊打算在人工智能领域率先取得进步&#xff0c;巩固其在技术领域的地…

【QT5-程序控制电源-[GPIB-USB-HS]-SCPI协议-上位机-基础样例【2】】

【QT5-程序控制电源-[GPIB-USB-HS]-SCPI协议-上位机-基础样例【2】】 1、前言2、实验环境3、自我总结1、基础了解仪器控制-熟悉仪器2、连接SCPI协议3、了解GPIB-USB-HS4、软件调试-代码编写 4、熟悉协议-SCPI协议5、实验过程-熟悉软件&#xff08;1&#xff09;去官网NI&#x…

玩转Linux—如何在Linux环境中部署MySQL、Redis和nginx

1、Linux常用命令 Linux学习之路&#xff1a; VMware虚拟机安装Linux系统(详解版) 查看当前文件目录&#xff1a;ls查看目录中文件详细信息&#xff1a;ll输出当前所处的目文件目录&#xff1a;pwdLinux查看当前IP地址&#xff1a;ifconfigWindows查看当前IP地址&#xff1…

MS31703H 桥栅极驱动控制器,可P2P替代TI的DRV8703

MS31703NA 是一款小型单通道 H 桥栅极驱动 器。它使用四个外部 N 通道 MOSFET &#xff0c;驱动一个双 向刷式直流电机。 PH/EN 、独立半桥或 PWM 允许轻松连接到控制 器电路。内部传感放大器提供可调的电流控制。集 成的电荷泵可提供 100% 占空比&#xff0c;而…

机械臂运动控制,通讯的解包->运动控制->数据封包上报过程

一、协议 数据格式为小端模式&#xff0c;浮点数格式为IEEE754&#xff0c;需与上位机的PC端一致&#xff0c;如window系统&#xff0c;其它系统需要自行测试&#xff0c;用于传输16位、32位、float数据格式&#xff0c;避免只传输字节数据带来转换的繁琐及精度丢失。 二、下位…

机器学习:随机森林

集成学习 集成学习&#xff08;Ensemble Learning&#xff09;是一种机器学习方法&#xff0c;通过将多个基本学习算法的预测结果进行组合&#xff0c;以获得更好的预测性能。集成学习的基本思想是通过结合多个弱分类器或回归器的预测结果&#xff0c;来构建一个更强大的集成模…

springboot+jsp+ssm高校图书馆图书借阅收藏评论管理系统617w1

本图书管理系统系统采用B/S架构&#xff0c;数据库是MySQL&#xff0c;网站的搭建与开发采用了先进的Java进行编写&#xff0c;使用了SSM&#xff08;Spring、SpringMVC、Mybits&#xff09;框架。该系统从两个对象&#xff1a;由管理员和用户来对系统进行设计构建。前台主要功…

面试题:在大型分布式系统中,给你一条 SQL,让你优化,你会怎么做?

亲爱的小伙伴们&#xff0c;大家好呀&#xff01;我是小米&#xff0c;一个热爱技术、乐于分享的90后程序猿。今天&#xff0c;我要和大家聊聊一个在大型分布式系统中非常有趣和挑战性的话题——如何优化 SQL 查询&#xff01; 这个问题可不简单&#xff0c;但不要担心&#x…

python练习4

前言&#xff1a;相信看到这篇文章的小伙伴都或多或少有一些编程基础&#xff0c;懂得一些linux的基本命令了吧&#xff0c;本篇文章将带领大家服务器如何部署一个使用django框架开发的一个网站进行云服务器端的部署。 文章使用到的的工具 Python&#xff1a;一种编程语言&…

Vue3最佳实践 第七章 TypeScript 创建Trello 任务管理器

| ​ 我们将探讨如何使用Vue.js从零开始创建一个类似于Trello的任务管理应用程序。如果你不熟悉Trello&#xff0c;它是一款非常流行的任务管理工具&#xff0c;允许你把任务写在卡片上&#xff0c;然后通过一个看板的方式来直观地管理这些任务。Trello不仅可以用于个人的任务…

电子地图 | VINS-FUSION | 小觅相机D系列

目录 一、相关介绍 二、VINS-FUSION环境安装及使用 &#xff08;一&#xff09;Ubuntu18.04安装配置 1、Ubuntu下载安装 2、设置虚拟内存&#xff08;可选&#xff09; &#xff08;二&#xff09;VINS-FUSION环境配置 1、ros安装 2、ceres-solver安装 3、vins-fusion…

JavaScript中的map()和forEach()方法有什么区别?

聚沙成塔每天进步一点点 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 欢迎来到前端入门之旅&#xff01;感兴趣的可以订阅本专栏哦&#xff01;这个专栏是为那些对Web开发感兴趣、刚刚踏入前端领域的朋友们量身打造的。无论你是完全的新手还是有一些基础的开发…

工信部教考中心:什么是《研发效能(DevOps)工程师》认证,拿到证书之后有什么作用!(上篇)丨IDCF

在计算机行业中&#xff0c;资质认证可以证明在该领域内的专业能力和知识水平。各种技术水平认证也是层出不穷&#xff0c;而考取具有公信力和权威性的认证是从业者的首选。同时&#xff0c;随着国内企业技术实力的提升和国家对于自主可控的重视程度不断提高&#xff0c;国产证…

基于Java的教学评价管理系统设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言系统功能结构图系统ER图具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09;有保障的售后福利 代码参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划…

Flink+Doris 实时数仓

Flink+Doris 实时数仓 Doris基本原理 Doris基本架构非常简单,只有FE(Frontend)、BE(Backend)两种角色,不依赖任何外部组件,对部署和运维非常友好。架构图如下 可以 看到Doris 的数仓架构十分简洁,不依赖 Hadoop 生态组件,构建及运维成本较低。 FE(Frontend)以 Java 语…

用 Pytorch 自己构建一个Transformer

一、说明 用pytorch自己构建一个transformer并不是难事,本篇使用pytorch随机生成五千个32位数的词向量做为源语言词表,再生成五千个32位数的词向量做为目标语言词表,让它们模拟翻译过程,transformer全部用pytorch实现,具备一定实战意义。 二、论文和概要 …

【数据结构--八大排序】之希尔排序

&#x1f490; &#x1f338; &#x1f337; &#x1f340; &#x1f339; &#x1f33b; &#x1f33a; &#x1f341; &#x1f343; &#x1f342; &#x1f33f; &#x1f344;&#x1f35d; &#x1f35b; &#x1f364; &#x1f4c3;个人主页 &#xff1a;阿然成长日记 …

STM32--人体红外感应开关

本文主要介绍基于STM32F103C8T6和人体红外感应开关实现的控制算法 简介 人体红外模块选用HC-SR501人体红外传感器&#xff0c;人体红外感应的主要器件为人体热释电红外传感器。人体都有恒定的体温&#xff0c;一般在36~37度&#xff0c;所以会发出特定波长的红外线&#xff0…