你知道vector底层是如何实现的吗?

你知道vector底层是如何实现的吗?

vector底层使用动态数组来存储元素对象,同时使用sizecapacity记录当前元素的数量和当前动态数组的容量。如果持续的push_back(emplace_back)元素,当size大于capacity时,需要开辟一块更大的动态数组,并把旧动态数组上的元素搬移到当前动态数组,然后销毁旧的动态数组。

你知道新开辟的动态数组的容量是就数组的多少倍比较合适?

这个值在不同的编译器上不是固定的。MSVC 是1.5,而GCC是2。

有没有什么好的办法提升vector连续插入效率?

如果知道数据的大概量,我们可以使用reserve方法直接为vector扩容这个量级。这样在后续的数据插入时就不会因为频繁的capacity被用尽而导致的多次的数据搬移,从而提升vector插入效率。

push_backemplace_back有什么区别?

两者都可以在容器尾部插入元素。在GCC中,如果插入的元素是右值,两者都会move元素到容器。如果是左值,两者都会copy元素到容器。唯一不同的一点是,当C++版本高于C++17时,emplace_back返回当前插入的值的引用,而push_back返回void

eraseremove有什么区别?

erase属于成员函数,erase删除了元素,remove属于算法库函数,而remove只会把元素移动到尾部。

哪些情况下迭代器会失效?

迭代器失效主要有两种情况引起:

1.插入数据。由于插入数据可能导致数据搬移(size > capacity),所以迭代器失效。

2.删除数据。当使用erase删除数据时,被删除数据后面的数据依次向前移一位。这会导致被删除数据之后的迭代器失效。

如何快速的清空vector容器并释放vector容器所占用的内存?

有两种方法:

  • 第一种,使用clear方法清空所有元素。然后使用shrink_to_fit方法把capacitysize(0)对齐,达到释放内存的作用;
  • 第二种,使用swap方法;
你知道vector<bool>是如何实现的吗?

vector<bool>的实现和其他实现容器的实现不一致。**每个元素被当作一个位而不是一个字节存储。**这导致我们不能直接访问该元素,也无法对每个元素取地址(8个元素可能在同一个字节中存储)。所以不建议使用vector<bool>,必要时可以使用std::bitset替代。

介绍三个和大小、容量与内存相关的函数:
  • 一个是_M_shrink_to_fit函数,可以使用这个函数将_M_finish和_M_end_of_storage之间的内存释放掉,正好使分配的内存大小满足vector中元素量。
  • 一个是reserve函数,可以使用这个函数控制整个vector容量的作用,避免重新分配内存,例如我们如果知道元素最多有80个,我们就可以使用v.reserve(80)来一次分配80个内存。但是值得注意的是这个函数不能用来缩减容量
  • 一个是resize函数,这个函数实际就是改变_M_start和_M_finish之间的相对位置,改变的是元素的个数,如果resize(n)的n小于当前个数就删除元素,如果大于就追加默认函数生成的对象。
vector是怎么变长的
typename vector<_Tp, _Alloc>::iterator
vector<_Tp, _Alloc>::insert(iterator __position, const value_type& __x)
{const size_type __n = __position – begin();//如果还有空位,插入到最后一个位置,相当于push_backif (this->_M_impl._M_finish != this->_M_impl._M_end_of_storage&& __position == end()){_Alloc_traits::construct(this->_M_impl, this->_M_impl._M_finish, __x);++this->_M_impl._M_finish;}else{_M_insert_aux(__position, __x);}return iterator(this->_M_impl._M_start + __n);
}

当容量不足的时候,就是_M_insert_aux函数发挥的时候,进行容量的扩展,实现如下:

template<typename _Tp, typename _Alloc>
void vector<_Tp, _Alloc>::_M_insert_aux(iterator __position, const _Tp& __x)
{//内存空间足够if (this->_M_impl._M_finish != this->_M_impl._M_end_of_storage){_Alloc_traits::construct(this->_M_impl, this->_M_impl._M_finish,_GLIBCXX_MOVE(*(this->_M_impl._M_finish- 1)));++this->_M_impl._M_finish;//__position后的元素依次向后移动一个位置_GLIBCXX_MOVE_BACKWARD3(__position.base(),this->_M_impl._M_finish - 2,this->_M_impl._M_finish – 1);//目标地址赋值*__position = _Tp(std::forward<_Args>(__args)...);}else{//内存加倍const size_type __len =_M_check_len(size_type(1), "vector::_M_insert_aux");const size_type __elems_before = __position - begin();pointer __new_start(this->_M_allocate(__len));pointer __new_finish(__new_start);__try{//给position位置赋值_Alloc_traits::construct(this->_M_impl,__new_start + __elems_before,std::forward<_Args>(__args)...);__x);__new_finish = 0;//拷贝position位置前元素__new_finish = std::__uninitialized_move_if_noexcept_a(this->_M_impl._M_start, __position.base(),__new_start, _M_get_Tp_allocator());++__new_finish;//拷贝position位置后元素__new_finish= std::__uninitialized_move_if_noexcept_a(__position.base(), this->_M_impl._M_finish,__new_finish, _M_get_Tp_allocator());}__catch(...){if (!__new_finish)_Alloc_traits::destroy(this->_M_impl,__new_start + __elems_before);elsestd::_Destroy(__new_start, __new_finish, _M_get_Tp_allocator());_M_deallocate(__new_start, __len);__throw_exception_again;}//析构原vector所有元素std::_Destroy(this->_M_impl._M_start, this->_M_impl._M_finish,_M_get_Tp_allocator());//释放原vector内存空间_M_deallocate(this->_M_impl._M_start,this->_M_impl._M_end_of_storage,this->_M_impl._M_start);//vector内存地址指向新空间this->_M_impl._M_start = __new_start;this->_M_impl._M_finish = __new_finish;this->_M_impl._M_end_of_storage = __new_start + __len;}
}

其中_M_check_len函数的实现如下:

size_type
_M_check_len(size_type __n, const char* __s) const
{if (max_size() - size() < __n)__throw_length_error(__N(__s));//如果n小于当前size,内存加倍,否则内存增长n。const size_type __len = size() + std::max(size(), __n);return (__len < size() || __len > max_size()) ? max_size() : __len;
}

可以发现vector内存分配策略并不是简单的加倍,如果n小于当前size,内存加倍,否则内存增长n。

接着我们讲一下vector怎么删除元素。vector删除元素的函数有以下几个:

// 删除某个位置上的元素,返回下一个元素的位置
erase(const_iterator __position)
// 删除一个区间内的所有元素
erase(const_iterator __first, const_iterator __last)
// 清空所有元素
clear()
// 借助remove删除与val相等的所有元素
erase(remove(begin(), end(), val), end());
// 借助remove_if删除满足某个条件的所有元素
erase(remove_if(begin(), end(), <lambda>), end());
vector使用陷阱
  • vector的函数除了at函数之外,都不抛出异常,如果要取元素的话,均需要判断是否越界,不然会引发未知的错误;

  • vector的内存占用空间只增不减,在使用vector时要及时清除元素和回收内存,尤其是在static对象中使用vector保存元素时。vector提供的删除元素的成员函数,只是调用元素的析构函数析构掉元素,已经分配的内存并不会收回;

  • 所有内存空间是在vector析构时候才能被系统回收。empty()用来检测容器是否为空的,clear()可以清空所有元素。但是即使clear(),vector所占用的内存空间依然如故,无法保证内存的回收。

  • 如果需要空间动态缩小,可以考虑使用deque。如果非vector不可,可以用swap()来帮助你释放内存。具体方法如下:

  • 如果vector中存放的是指针,那么当vector销毁的时候,这些指针指向的对象不会被销毁,所占用的内存也不会被释放。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【InternLM 实战营笔记】XTuner 大模型单卡低成本微调实战

XTuner概述 一个大语言模型微调工具箱。由 MMRazor 和 MMDeploy 联合开发。 支持的开源LLM (2023.11.01) InternLM Llama&#xff0c;Llama2 ChatGLM2&#xff0c;ChatGLM3 Qwen Baichuan&#xff0c;Baichuan2 Zephyr 特色 傻瓜化&#xff1a; 以 配置文件 的形式封装了大…

WebGIS----wenpack

学习资料&#xff1a;https://webpack.js.org/concepts/ 简介&#xff1a; Webpack 是一个现代化的 JavaScript 应用程序的模块打包工具。它能够将多个 JavaScript 文件和它们的依赖打包成一个单独的文件&#xff0c;以供在网页中使用。 Webpack 还具有编译和转换其他类型文…

自学新标日第六课(单词部分 未完结)

第六课 单词 单词假名声调词义来月らいげつ1下个月先月せんげつ1上个月夜中よなか3午夜昨夜ゆうべ0昨天晚上コンサートこんさーと1音乐会クリスマスくりすます3圣诞季誕生日たんじょうび&#xff13;生日こどもの日こどものひ&#xff15;儿童节夏休みなつやすみ&#xff13;…

看待事物的层与次 | DBA与架构的一次对话交流

前言 在计算机软件业生涯中,想必行内人或多或少都能感受到系统架构设计与数据库系统工程的重要性,也能够清晰地认识到在计算机软件行业中技术工程师这个职业所需要的专业素养和必备技能! 背景 通过自研的数据库监控管理工具,发现 SQL Server 数据库连接数在1-2K之间,想…

Yii2中如何使用scenario场景,使rules按不同运用进行字段验证

Yii2中如何使用scenario场景&#xff0c;使rules按不同运用进行字段验证 当创建news新闻form表单时&#xff1a; 添加新闻的时候执行create动作。 必填字段&#xff1a;title-标题&#xff0c;picture-图片&#xff0c;description-描述。 这时候在model里News.php下rules规则…

星座每日运势 api接口

接口数据api 接口平台&#xff1a;https://api.yuanfenju.com/ 开发文档&#xff1a;https://doc.yuanfenju.com/zhanbu/yunshi.html 支持格式&#xff1a;JSON 请求方式&#xff1a;HTTP POST <?php//您的密钥 $api_secret "wD******XhOUW******pvr"; //请…

利用coze 搭建“全功能“微信客服(2)

紧跟上篇 利用coze 搭建"全功能"微信客服&#xff08;1&#xff09;&#xff0c;不知道来龙去脉自行查阅 先表扬下coze: coze 是国内少数开放平台之一&#xff0c;里面提供各种插件还可以开发工作流&#xff0c;让你可以实现多模态全功能大模型 吐槽 没有API开放接口…

国外最流行的是AI,国内最流行的是AI培训教程

国外最流行的是AI&#xff0c;国内最流行的是AI培训教程。 最近李一舟AI教程事件&#xff0c;验证了这句话。 如今给客户做方案项目里能加点AI色彩&#xff0c;立项的成功率都变大(特别是事业单位)。 正因如此&#xff0c;大家都在狂补AI的知识&#xff0c;不然肚子里没点墨水&…

2024亚马逊全球开店注册前需要准备什么?

在2023年出海四小龙SHEIN、Temu、速卖通AliExpress、TikTok Shop快速增长扩张&#xff0c;成为了中国跨境卖家“逃离亚马逊”的新选择。但是&#xff0c;跨境电商看亚马逊。当前&#xff0c;亚马逊仍然是跨境电商行业的绝对老大&#xff0c;占有将近70%成以上的业务份额。 作为…

threejs显示本地硬盘上的ply文件,通过webapi

由于ply文件是第三方提供的&#xff0c;threejs无法用绝路路径的方式显示ply 所以想通过webapi把ply通过url地址的方式给threejs 1.webapi部分 /// <summary>/// 获取PLY文件/// </summary>/// <returns></returns>[HttpPost(Name "GetPly&qu…

分享fastapi低级错误

我是创建表的时候把__tablename__ 写成__table__然后一直报这个错误

Android Activity跳转详解

在Android应用程序中&#xff0c;Activity之间的跳转是非常常见的操作&#xff0c;通过跳转可以实现不同界面之间的切换和交互。在本篇博客中&#xff0c;我们将介绍Android中Activity跳转的相关知识&#xff0c;包括基本跳转、传递参数、返回数据以及跳转到浏览器、拨号应用和…

端游如何防破解

在2023年这个游戏大年中&#xff0c;诸多热门大作涌现&#xff0c;作为世界级IP哈利哈利波特的衍生游戏——《霍格沃茨之遗》毫无悬念地成为2023年游戏圈的首款爆款作品&#xff0c;斩获了一众玩家的青睐。 在众多光环的加持下&#xff0c;《霍格沃茨之遗》很快被著名游戏破解…

【每日前端面经】2024-03-01

题目来源: 牛客 MVVM怎么实现 MVVM分别指View、Model、ViewModel&#xff0c;View通过View-Model的DOM监听器将事件绑定到Model上&#xff0c;而Model则通过Data Bindings来管理View中的数据&#xff0c;View-Model从中起到一个连接的作用 响应式: vue如何监听data的属性变化…

深入 Starknet 去中心化世界,探秘实用开发利器

Starknet 近期开放空投&#xff0c;面向 130 万地址总量发放超 7 亿枚 Token&#xff0c;让 ECMP 早期贡献者、GitHub 开源开发者、Starknet 用户等各个层面的生态参与者都得以深度参与。 盛宴的背后&#xff0c;是 Starknet 正迎来发展的关键机遇。在今年以太坊坎昆升级的背景…

从别人的开源项目学习并吸收经验,然后逐步搭建自己的Java项目是一个很好的学习方法

从别人的开源项目学习并吸收经验&#xff0c;然后逐步搭建自己的Java项目是一个很好的学习方法。以下是一些建议的步骤&#xff0c;帮助你从0开始搭建并不断完善自己的Java项目&#xff0c;直至达到高可靠、高稳定、高并发、高数据安全&#xff0c;并可以拆分为微服务的大型高质…

【漏洞复现】某厂商上网行为管理系统static_convert命令执行漏洞

Nx01 产品简介 天融信上网行为管理系统是天融信公司凭借多年来的安全产品研发经验&#xff0c;为满足各行各业进行网络行为管理和内容审计的专业产品。 Nx02 漏洞描述 天融信上网行为管理系统老版本static_convert.php接口存在RCE漏洞&#xff0c;攻击者利用此漏洞可以获取服务…

超强预测算法:XGBoost预测模型

目录 往期精彩内容&#xff1a; 多变量特征序列、单序列数据预测实战 前言 1 风速数据预处理与数据集制作 1.1 导入数据 1.2 多变量数据预处理与数据集制作 1.3 单序列数据预处理与数据集制作 2超强模型XGBoost——原理介绍 3 模型评估和对比 3.1 随机森林预测模型 3…

基于NeRF/Gaussian的全新SLAM算法

什么是SLAM&#xff1f; SLAM&#xff0c;即同时定位与地图构建技术&#xff0c;SLAM可以让机器人、无人机和其他自动化系统能够在未知环境中同时进行自我定位和环境映射。 为什么是NeRF-Based SLAM&#xff1f; 传统CG将输入图像重新投影再融合到新的视图摄像机中&#xff0c…

InfiniBand 200Gbps QSFP56 高速线缆/光缆和光模块解决方案

随着数据中心和人工智能迅速发展&#xff0c;对高速、低延迟和低功耗的数据传输需求变得至关重要。飞速&#xff08;FS&#xff09;提供针对各种高性能计算场景量身定制的各种InfiniBand线缆和光模块产品。本文旨在概述飞速&#xff08;FS&#xff09;200G InfiniBand HDR 光缆…