std::vector

这里主要介绍下reserce/resize、push_back/emplace_back、shrink_to_fit/clear等接口;

1. reserve and resize

       C++的vector对象可以通过reserve方法来设置vector对象的容量,通过resize方法来改变vector对象的大小。reserve所设置的容量指的是vector容器中可容纳元素的预留空间个数,但并不真正创建元素对象。resize则是直接改变vector容器中元素的个数,并且创建对象或者销毁空间。

       resize()函数和容器的size息息相关。调用resize(n)后,容器的size即为n。至于是否影响capacity,取决于调整后的容器的size是否大于capacity。

reserve()函数和容器的capacity息息相关。调用reserve(n)后,若容器的capacity<n,则重新分配内存空间,从而使得capacity等于n。

如果capacity>=n呢?capacity无变化。

       从两个函数的用途可以发现,容器调用resize()函数后,所有的空间都已经初始化了,所以可以直接访问。

        而reserve()函数预分配出的空间没有被初始化,所以不可访问。

#include <iostream>
#include <vector>
#include <string>
#include <map>
 
using ValueType = std::string;
const ValueType dv = "aaaaaaaaaaaaaaaaaaaaaaaa";
constexpr int maxSize = 10;
 
class Widget {
public:
	Widget(ValueType value = dv) : value{value}
	{
	    std::cout << "Widget(ValueType) constructor: " << this << std::endl;
	}
 
	Widget(const Widget& w) : value{w.value}
	{
	    std::cout<<"copy constructor" << std::endl;
	}
	Widget& operator=(const Widget& rhs)
	{
        if (this != &rhs)
        {
	        value = rhs.value;//assign new resource
        }
 
	    std::cout << "copy assignment constructor" << std::endl;
	    return *this;
	}
	//这里移动构造函数定义为noexcept
	Widget(Widget&& w) noexcept: value{std::move(w.value)}
	{
		std::cout << "move constructor" << std::endl;
	}
	Widget& operator=(Widget&& rhs)
	{
        if (this != &rhs)
        {
	        value = std::move(rhs.value);//assign new resource
        }
	    std::cout << "move assignment constructor" << std::endl;
	    return *this;
	}
 
    ~Widget()
	{
        if (value.empty())
        {
            std::cout << "0~destructor:" << this << std::endl;
        }
        else
        {
            value.clear();
	        std::cout << "~destructor:" << this << std::endl;
        }
	}
	void print(){std::cout << "value:" << value << " : " << this << std::endl;}
private:
	ValueType value{};
};

void test_reserve()
{
    std::vector<Widget> v{Widget{"aaaaaaaaaaaaaaaaaaaaaaaa"}, Widget{"bbbbbbbbbbbbbbbbbbbbbbbb"}, Widget{"ccccccccccccccccccccccc"}};
    std::cout << "size()=" << v.size() << ", capacity()=" << v.capacity() << std::endl << std::endl;
    
    v.reserve(2);//当reserve的数据空间小于capacity的时候什么都不做;
    std::cout << "size()=" << v.size() << ", capacity()=" << v.capacity() << std::endl << std::endl;
    
    //当reserve的数据空间大于capacity时,vector的capacity变为reserve指定的大校
    v.reserve(5);//由于要重新分配比 3 更大的存储空间,这里再次调用的移动构造函数(如果移动构造函数没有noexcept,则调用拷贝构造函数)
    std::cout << "size()=" << v.size() << ", capacity()=" << v.capacity() << std::endl << std::endl;
    
    v.reserve(4);
    std::cout << "size()=" << v.size() << ", capacity()=" << v.capacity() << std::endl << std::endl;
    
    v.reserve(2);
    std::cout << "size()=" << v.size() << ", capacity()=" << v.capacity() << std::endl << std::endl;
}

void test_resize()
{
    std::vector<Widget> v{Widget{"aaaaaaaaaaaaaaaaaaaaaaaa"}, Widget{"bbbbbbbbbbbbbbbbbbbbbbbb"}, Widget{"ccccccccccccccccccccccc"}};
    std::cout << std::endl;
    std::cout << "size()=" << v.size() << ", capacity()=" << v.capacity() << std::endl << std::endl;
    v.resize(5);//vector重新分配空间(需要移动/拷贝原数据),resize的空间大于size()时,会构造 5 - size()个数据项(这里是构造2个新的Widget)
    std::cout << "size()=" << v.size() << ", capacity()=" << v.capacity() << std::endl << std::endl;
    
    v.resize(4);//destory多余指定size的数据项
    std::cout << "size()=" << v.size() << ", capacity()=" << v.capacity() << std::endl << std::endl;
    
    v.resize(2);//destory多余指定size的数据项
    std::cout << "size()=" << v.size() << ", capacity()=" << v.capacity() << std::endl << std::endl;
}

int main()
{
    test_reserve();
    std::cout << "----------------------" << std::endl;
    test_resize();
    
    return 0;
}

output:

2. vector(count, value) vs reserve(n)

这里有一个点需要注意下:vector( size_type count,

                                                        const T& value, 

                                                        const Allocator& alloc = Allocator() );

和 vector.reserve的区别, 这个vector会构造数据项,而reserve不构造数据项,只是预留了空间;

#include <iostream>
#include <vector>

void test_vector_constructor_vs_reserve()
{
    std::vector<int> v1(2,3);
    std::cout << "size()=" << v1.size() << ", capacity()=" << v1.capacity() << std::endl << std::endl;
    for(const auto i : v1)
    {
        std::cout << i << ' ';
    }
    std::cout << std::endl;
    
    std::vector<int> v2{};
    v2.reserve(2);//当reserve的数据空间小于capacity的时候什么都不做;
    std::cout << "size()=" << v2.size() << ", capacity()=" << v2.capacity() << std::endl << std::endl;
}

int main()
{
    test_vector_constructor_vs_reserve();
    
    return 0;
}

 3. shrink_to_fit vs clear

shrink_to_fit() : 它减少容器的容量以适应其大小并销毁超出容量的所有元素。

clear():从容器擦除所有元素。此调用后 size() 返回零。使任何指代所含元素的引用、指针或迭代器失效。任何尾后迭代器也会失效。  保持 vector 的 capacity() 不变。

#include <iostream>
#include <vector>
#include <string>
 
using ValueType = std::string;
const ValueType dv = "aaaaaaaaaaaaaaaaaaaaaaaa";
constexpr int maxSize = 10;
 
class Widget {
public:
	Widget(ValueType value = dv) : value{value}
	{
	    std::cout << "Widget(ValueType) constructor: " << this << std::endl;
	}
 
	Widget(const Widget& w) : value{w.value}
	{
	    std::cout<<"copy constructor" << std::endl;
	}
	Widget& operator=(const Widget& rhs)
	{
        if (this != &rhs)
        {
	        value = rhs.value;//assign new resource
        }
 
	    std::cout << "copy assignment constructor" << std::endl;
	    return *this;
	}
	//这里移动构造函数定义为noexcept
	Widget(Widget&& w) noexcept: value{std::move(w.value)}
	{
		std::cout << "move constructor" << std::endl;
	}
	Widget& operator=(Widget&& rhs)
	{
        if (this != &rhs)
        {
	        value = std::move(rhs.value);//assign new resource
        }
	    std::cout << "move assignment constructor" << std::endl;
	    return *this;
	}
 
    ~Widget()
	{
        if (value.empty())
        {
            std::cout << "0~destructor:" << this << std::endl;
        }
        else
        {
            value.clear();
	        std::cout << "~destructor:" << this << std::endl;
        }
	}
	void print(){std::cout << "value:" << value << " : " << this << std::endl;}
private:
	ValueType value{};
};

void test_shrink_to_fit()
{
    std::vector<Widget> v;

    std::cout << "size()=" << v.size() << ", capacity()=" << v.capacity() << std::endl << std::endl;
    v.emplace_back(std::string(24, 'a'));
    v.emplace_back(std::string(24, 'b'));
    v.emplace_back(std::string(24, 'c'));
    v.emplace_back(std::string(24, 'd'));
    v.emplace_back(std::string(24, 'e'));
    
    std::cout << "size()=" << v.size() << ", capacity()=" << v.capacity() << std::endl << std::endl;
    
    v.shrink_to_fit();//按照我测试结果,测试capacity=8, size为添加的5个元素;
                      //shrink_to_fit会释放掉多余的vector空间,使得capacity()==size();
                      //这里可能会重新分配空间,具体依赖于编译器的实现
    std::cout << "size()=" << v.size() << ", capacity()=" << v.capacity() << std::endl << std::endl;
}

void test_clear()
{
    std::vector<Widget> v{Widget{"aaaaaaaaaaaaaaaaaaaaaaaa"}, Widget{"bbbbbbbbbbbbbbbbbbbbbbbb"}, Widget{"ccccccccccccccccccccccc"}};
    
    std::cout << "size()=" << v.size() << ", capacity()=" << v.capacity() << std::endl << std::endl;
    std::cout << "call clear():" << std::endl;;
    v.clear();//会把所有数据项destory掉,此时size()大小为0, capacity则不变;
    std::cout << "size()=" << v.size() << ", capacity()=" << v.capacity() << std::endl << std::endl;
    
}

int main()
{
    test_shrink_to_fit();
    std::cout << std::endl << "----------------------" << std::endl << std::endl;
    test_clear();
    
    return 0;
}

4. push_back vs emplace_back

push_back:是插入数据到vector,这里会构造一个临时的数据项,这个临时数据项参数满足push_back(T&& value)接口,通过移动构造函数把这个临时的数据项移动到vector对应的位置上;

emplace_back:是通过完美转发参数,在vector对应的位置上就地构造,只需要调用一次构造函数就可以;这种情况下,效率上来说要比push_back高一些;

对于push_back和emplace_back来说,如果传入的数据项本身是个左值,那么他们效率上都是一样的。因为这两个接口都只需要调用一次拷贝构造函数。代码如下:

#include <iostream>
#include <vector>
#include <string>
#include <map>
 
using ValueType = std::string;
const ValueType dv = "aaaaaaaaaaaaaaaaaaaaaaaa";
constexpr int maxSize = 10;
 
class Widget {
public:
	Widget(ValueType value = dv) : value{value}
	{
	    std::cout << "Widget(ValueType) constructor: " << this << std::endl;
	}
 
	Widget(const Widget& w) : value{w.value}
	{
	    std::cout<<"copy constructor" << std::endl;
	}
	Widget& operator=(const Widget& rhs)
	{
        if (this != &rhs)
        {
	        value = rhs.value;//assign new resource
        }
 
	    std::cout << "copy assignment constructor" << std::endl;
	    return *this;
	}
	Widget(Widget&& w) : value{std::move(w.value)}
	{
		std::cout << "move constructor" << std::endl;
	}
	Widget& operator=(Widget&& rhs)
	{
        if (this != &rhs)
        {
	        value = std::move(rhs.value);//assign new resource
        }
	    std::cout << "move assignment constructor" << std::endl;
	    return *this;
	}
 
    ~Widget()
	{
        if (value.empty())
        {
            std::cout << "0~destructor:" << this << std::endl;
        }
        else
        {
            value.clear();
	        std::cout << "~destructor:" << this << std::endl;
        }
	}
	void print(){std::cout << "value:" << value << " : " << this << std::endl;}
private:
	ValueType value{};
};
void push_vs_empalce_with_rvalue_item()
{
    std::vector<Widget> v{};
    v.reserve(10);
    std::cout << std::endl;
    
    std::string str(24, 'a');
    v.push_back(str);
    std::cout << std::endl;
    
    v.emplace_back(str);
    std::cout << std::endl;
    
}
void push_vs_empalce_with_lvalue_item()
{
    Widget w1("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
    Widget w2("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb");
    std::vector<Widget> v{};
    v.reserve(10);
    
    std::cout << std::endl;
    v.push_back(w1);
    std::cout << std::endl;
    
    v.emplace_back(w2);
    std::cout << std::endl;
}

int main()
{
    push_vs_empalce_with_rvalue_item();
    std::cout << std::endl << "-------------------------" << std::endl << std::endl;
    push_vs_empalce_with_lvalue_item();
    
    return 0;
}

output:

 

后续再介绍vector插入数据的性能等;

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

0基础学习VR全景平台篇第127篇:什么是VR全景/720全景漫游?

“全景”作为一种表现宽阔视野的手法&#xff0c;在很久之前就得到了普遍的认同。北宋年间&#xff0c;由张择端绘制的《清明上河图》就是一幅著名的全景画。摄影术出现后&#xff0c;全景摄影也随之而生。 到今天&#xff0c;全景拍摄不再被专业摄影师所独享&#xff0c;广大…

云计算与AI融合:Amazon Connect开创客户服务智能时代

授权说明&#xff1a;本篇文章授权活动官方亚马逊云科技文章转发、改写权&#xff0c;包括不限于在 亚马逊云科技开发者社区, 知乎&#xff0c;自媒体平台&#xff0c;第三方开发者媒体等亚马逊云科技官方渠道 在亚马逊云科技 re:Invent 2023 大会上&#xff0c;Amazon Connect…

[AutoSar]状态管理(四)单核BswM(二)流程、配置、 代码

目录 关键词平台说明一、BswM的模式处理流程图二、stand state handling三、配置、代码、状态转移3.1 initial -> wakeup   3.2 WakeUp -> Run3.3 Run -> PostRun &#xff08;first step&#xff09;3.4 Run -> PostRun &#xff08;second step&#xff09;3.5…

Python安装报错: This environment is externally managed

error: externally-managed-environment This environment is externally managed ╰─> To install Python packages system-wide, try apt installpython3-xyz, where xyz is the package you are trying toinstall.这个错误信息表示当前Python环境是由系统外部管理的&…

基于Docker-Compose实现ELK+Kafka搭建分布式日志采集系统

ELKKafka搭建日志采集系统 ELK概述搭建与配置docker-compose.yml配置日志采集规则启动服务 模拟发送日志消息日志发送队列日志切面配置application.yaml发送日志消息 Kibana的使用创建索引模式Discovery搜索数据可视化数据 ELKRabbitMQ发送日志消息配置日志采集规则 ELK概述 E…

Java IO 流详解

Java IO 流详解 1 .Java IO概念 Java IO&#xff1a;即 Java 输入 / 输出系统。 Java 的 IO 模型设计非常优秀&#xff0c;它使用 Decorator (装饰者)模式&#xff0c;按功能划分 Stream &#xff0c;您可以动态装配 这些 Stream &#xff0c;以便获得您需要的功能。 Stream &…

20 Redis进阶 - 运维监控

1、理解Redis监控 Redis运维和监控的意义不言而喻&#xff0c;可以以下三个方面入手 1.首先是Redis自身提供了哪些状态信息&#xff0c;以及有哪些常见的命令可以获取Redis的监控信息; 2.一些常见的UI工具可以可视化的监控Redis; 3.理解Redis的监控体系;2、Redis自身状态及命…

【Java反射详解】

Java反射详解 &#x1f38a;专栏【Java】 &#x1f354;喜欢的诗句&#xff1a;关山难越&#xff0c;谁悲失路之人。 萍水相逢&#xff0c;尽是他乡之客。 &#x1f386;音乐分享【Counting Stars 】 欢迎并且感谢大家指出问题&#x1f970; 1.什么是反射 所谓的反射就是java…

365锦鲤助手 砍价小程序源码 流量主引流裂变

源码介绍 修改版365锦鲤 助手&#xff0c; 砍价小程序源码 流量主引流裂变 拼多多商品快速丰富产品内容满足广大用户需求&#xff1b;流量矩阵让流量都进你的圈子飞起来&#xff1b;长期盈利、项目稳定 1.后台安装微擎 2安装应用 后台打包上传

PPINN Parareal physics-informed neural network for time-dependent PDEs

论文阅读&#xff1a;PPINN Parareal physics-informed neural network for time-dependent PDEs PPINN Parareal physics-informed neural network for time-dependent PDEs简介方法PPINN加速分析 实验确定性常微分方程随机常微分方程Burgers 方程扩散反应方程 总结 PPINN Par…

Npm安装vue3报错(node:25436) MaxListenersExceededWarning:

运行命令安装vue3时 npm create vuelatest 报了错误(node:25436) MaxListenersExceededWarning: (忘记截报错的图了&#xff0c;后面还有一大串英文) 搞了很久发现是网络的原因&#xff0c;我没有修改镜像地址&#xff0c;导致访问很慢&#xff0c;于是去npmmirror 镜像站 …

字符雨canvas

整体思路&#xff1a; 确定好字符雨的具体字符是什么&#xff0c;需要多少行多少列这里是写死的其实也可以用循环加随机的方式生成不一样的字符雨&#xff0c;行列也可以读一下宽度然后做一下出发算一下也行首先得有一张画布搞起&#xff0c;然后循环列数去绘画字符定时器循环…

泰森多边形半平面求交 - 洛谷 - P3297 [SDOI2013] 逃考

欢迎关注更多精彩 关注我&#xff0c;学习常用算法与数据结构&#xff0c;一题多解&#xff0c;降维打击。 往期相关背景半平面求交 点击前往 voronoi 图求解点击前往 题目大意 题目链接 https://www.luogu.com.cn/problem/P3297 小杨家是一个矩阵&#xff0c;所有亲戚都在…

Monkey工具之fastbot-iOS实践

背景 目前移动端App上线后 crash 率比较高&#xff0c; 尤其在iOS端。我们需要一款Monkey工具测试App的稳定性&#xff0c;更早的发现crash问题并修复。 去年移动开发者大会上有参加 fastbot 的分享&#xff0c;所以很自然的就想到Fastbot工具。 Fastbot-iOS安装配置 准备工…

变电站蓄电池在线监测系统(论文+源码)

1. 系统设计 本次课题为变电站蓄电池在线监测系统的设计&#xff0c;其系统架构如图3.1所示&#xff0c;包括了主控制器STC89C52单片机&#xff0c;液晶显示器LCD1602,模数转换器ADC0832&#xff0c;电流传感器ACS712&#xff0c;分压电阻&#xff0c;蜂鸣器以及温度传感器。在…

实用篇 | 3D建模中Blender软件的下载及使用[图文详情]

本文基于数字人系列的3D建模工具Blender软件的安装及使用&#xff0c;还介绍了图片生成3D模型的AI工具~ 目录 1.Blender的下载 2.Blender的使用 3.安装插件(通过压缩包安装) 4.实例 4.1.Blender使用MB-Lab插件快速人体模型建构 4.1.1.点击官网&#xff0c;进行下载 4.1.…

消息可靠性保证

回顾RabbitMQ的消息传递过程 如图所示&#xff0c;发生消息丢失的可能阶段也就是生产者发送消息&#xff0c;时rabbitmq存储消息时&#xff0c;消费者消费消息时。项目源码&#xff1a;gitee 生产者发送消息阶段 生产者发送消息时把交换机名写错生产者发送消息时把routingK…

推荐一款好用的包含表格识别的OCR网站

在当今数字化的时代&#xff0c;文字和表格识别已经成为了许多行业的关键技术。无论是处理大量的纸质文档&#xff0c;还是从网络上收集数据&#xff0c;OCR&#xff08;光学字符识别&#xff09;技术都扮演着重要的角色。然而&#xff0c;对于许多用户来说&#xff0c;OCR软件…

Infobright列存数据库原理介绍

简介 Infobright 是一个面向 OLAP 场景的开源列存数据库。比较容易找到代码的版本是 Infobright Community Edition 4.0.7&#xff0c;大概是 2006 年前后的代码。2016 年6 月&#xff0c;Infobright 决定停止开源1。由于它同时提供企业版和社区版&#xff0c;开源版本的功能相…

斑马zebra目标检测数据集VOC+YOLO格式2300张

斑马是由四百万年前的原马进化出来的&#xff0c;最早出现的斑马可能是细纹斑马。有关史前马科动物的化石现存于美国爱达荷州克文的克文化石床国家博物馆。斑马的史前马为“克文马”&#xff08;美洲斑马或者克文斑马&#xff09;&#xff0c;学名为“Equussimplicidens”&…