C++的vector使用优化
我们在上一章说了如何使用这个vector动态数组,这章我们说说如何更好的使用它以及它是如何工作的。当你创建一个vector,然后使用push_back添加元素,当当前的vector的内存不够时,会从内存中的旧位置复制到内存中的新位置,然后删除删除旧位置的内存,也就是说当我push_back,vector容量不够添加元素就会调整大小,重新分配,这也就是将代码拖慢的原因之一。是事实,我们需要不断的重新分配,这是一个非常缓慢的操作,应该避免。我们如何避免复制对象,如果我们处理的是vector,特别是基于vector的对象,我们没有存储vector指针,我们存储的是vector对象,那占的内存就更大了,所以我们要优化复制。
#include <iostream>
#include <string>
#include <vector>struct Vertex
{float x, y, z;Vertex(float x, float y, float z): x(x), y(y), z(z){}//拷贝构造Vertex(const Vertex& vertex): x(vertex.x), y(vertex.y), z(vertex.z){std::cout << "Copied!" << std::endl;}
};int main()
{std::vector<Vertex> vertices;//打印6次//vertices.push_back(Vertex(1, 2, 3));//vertices.push_back(Vertex(4, 8, 9));//vertices.push_back(Vertex(7, 5, 6));//打印3次vertices.reserve(3);vertices.push_back(Vertex(1, 2, 3));vertices.push_back(Vertex(4, 8, 9));vertices.push_back(Vertex(7, 5, 6));std::cin.get();//打印0次vertices.emplace_back(1, 2, 3);vertices.emplace_back(14, 4, 6);vertices.emplace_back(7, 8, 9);}



在上面这段代码中,我们复制了6次(调用了6次拷贝构造函数),这个是为什么呢?当我们在push_back的时候,我们实际是在,主函数的当前帧中构造它,所以我们在main的栈上创建它,然后我们需要做的是,把它放到这个vector中,所以我们是从main函数中(把这个创建的vertex)放到实际的vector中。
在 C++ 中,std::vector 是一个动态数组,它可以调整其大小以容纳不同数量的元素。当你调用 reserve 方法时,你告诉 vector 它应该预先分配足够的内存来存储指定数量的元素,但并不会真正添加这些元素。这样做的好处是,当你稍后添加元素到 vector 时,它可能不需要重新分配内存(如果添加的元素数量没有超过预留的数量),这可以提高效率,因为内存分配通常是一个昂贵的操作。
在我们的代码中,由于预留了 3 个元素的空间,因此当你添加前三个元素时,不需要重新分配内存,所以不会调用拷贝构造函数(除了可能的隐式移动构造函数或复制省略,但这些在这个例子中都不适用,因为直接传递了临时对象)。但是,如果你没有调用 reserve,并且 vector 的初始容量小于你要添加的元素数量,那么在添加元素时可能需要重新分配内存。在重新分配内存时,旧的元素会被拷贝(或移动)到新的内存位置,这就会调用拷贝构造函数(或移动构造函数)。
当你使用 vertices.emplace_back(1, 2, 3);(以及类似的 emplace_back 调用)时,你实际上是在告诉 std::vector 直接在其内部存储中构造 Vertex 对象,而不是先创建一个临时对象然后再将其拷贝或移动到 vector 中。这是 emplace_back 相较于 push_back 的主要优势之一,因为它避免了不必要的拷贝或移动操作,从而提高了效率。
由于 emplace_back 直接在 vector 的内存中构造对象,它不会调用 Vertex 的拷贝构造函数。相反,它会调用 Vertex 的构造函数,直接传递参数给构造函数来构造对象。这就是为什么你在使用 emplace_back 后没有看到 "Copied!" 的输出。而是三次Constructed!
#include <iostream>
#include <string>
#include <vector>struct Vertex
{float x, y, z;Vertex(float x, float y, float z): x(x), y(y), z(z){std::cout << "Constructed!" << std::endl;}//拷贝构造Vertex(const Vertex& vertex): x(vertex.x), y(vertex.y), z(vertex.z){std::cout << "Copied!" << std::endl;}
};int main()
{std::vector<Vertex> vertices;vertices.reserve(3);vertices.emplace_back(1, 2, 3);vertices.emplace_back(14, 4, 6);vertices.emplace_back(7, 8, 9);std::cin.get();
}
运行上述代码,你会看到 "Constructed!" 被打印了3次,而不是 "Copied!",因为 emplace_back 直接在 vector 的内存中构造了 Vertex 对象。

相关文章:
C++的vector使用优化
我们在上一章说了如何使用这个vector动态数组,这章我们说说如何更好的使用它以及它是如何工作的。当你创建一个vector,然后使用push_back添加元素,当当前的vector的内存不够时,会从内存中的旧位置复制到内存中的新位置,…...
关于stm32的复用和重映射问题
目录 需求IO口的复用和重映射使用复用复用加重映射 总结参考资料 需求 一开始使用stm32c8t6,想实现pwm输出,但是原电路固定在芯片的引脚PB10和PB11上,查看了下引脚的功能,需要使用到复用功能。让改引脚作为定时器PWM的输出IO口。…...
遍历数组1
package demo; import java.util.ArrayList; public class Arrilist { public static void main(String[] args) { ArrayList<String>listnew ArrayList<>(); list.add("汤神"); list.add("yyx"); list.add("hong go…...
Go语言 一些问题了解
一、读取文件数据,是阻塞还是非阻塞的? 分两种情况:常规读取文件数据,和网络IO读取数据 1. 常规读取文件数据: io.Reader 和 bufio.Reader 是阻塞进行的。 bufio.Reader 提供缓冲的读取操作,意味着数据是…...
C++ Primer 第五版 第15章 面向对象程序设计
面向对象程序设计基于三个基本概念:数据抽象、继承和动态绑定。 继承和动态绑定对编写程序有两方面的影响:一是我们可以更容易地定义与其他类相似但不完全相同的新类;二是在使用这些彼此相似的类编写程序时,我们可以在一定程度上…...
finebi或者finereport发邮件
我们二次开发中,如果想利用产品自带的发邮件的功能,来发送自己的邮件内容。 首先 决策系统中邮件相关信息要配置好之后: 这里配好了发件人,以及默认发件人后, private void sendEmail(String content,String subject)…...
基于聚类和回归分析方法探究蓝莓产量影响因素与预测模型研究
🌟欢迎来到 我的博客 —— 探索技术的无限可能! 🌟博客的简介(文章目录) 目录 背景数据说明数据来源思考 正文数据预处理数据读取数据预览数据处理 相关性分析聚类分析数据处理确定聚类数建立k均值聚类模型 多元线性回…...
【数据结构】从前序与中序遍历,或中序与后序遍历序列,构造二叉树
欢迎浏览高耳机的博客 希望我们彼此都有更好的收获 感谢三连支持! 首先,根据先序遍历可以确定根节点E,再在中序遍历中通过E确定左树和右数 ; 设立inBegin和inEnd,通过这两个参数的游走,来进行子树的创建&a…...
ARM公司发展历程
Arm从1990年成立前开始,历经漫长岁月树立各项公司里程碑及产品成就,一步步成为全球最普及的运算平台。 添加图片注释,不超过 140 字(可选) Acorn 时期 1978年,Chris Curry和Hermann Hauser共同创立了Acorn…...
C# :IQueryable IEnumerable
文章目录 1. IEnumerable2. IQueryable3. LINQ to SQL4. IEnumerable & IQueryable4.1 Expression4.2 Provider 1. IEnumerable namespace System.Collections: public interface IEnumerable {public IEnumerator GetEnumerator (); }public interface IEnumerator {pubi…...
三、生成RPM包
文章目录 1、编译生成so、bin 通过此工程编译生成so\bin文件 2、将so\bin打包到rpm中 ###### 1.生成可执行文件、库文件 ######### cmake_minimum_required(VERSION 3.15)project(compute) set(target zls_bin) set(target2 libcompute.so) # 依赖的头文件 include_directori…...
单实例11.2.0.4迁移到11.2.0.4RAC_使用rman异机恢复
保命法则:先备份再操作,磁盘空间紧张无法备份就让满足,给自己留退路。 场景说明: 1.本文档的环境为同平台、不同版本(操作系统版本可以不同,数据库版本相同),源机器和目标机器部分…...
MySQL之查询性能优化(二)
查询性能优化 慢查询基础:优化数据访问 查询性能低下最基本的原因是访问的数据太多。某些查询可能不可避免地需要筛选大量数据,但这并不场景。大部分性能低下的查询都可以通过减少访问的数据量的方式进行优化。对于低效的查询,我们发现通过下面两个步骤…...
The Best Toolkit 最好用的工具集
The Best Toolkit 工欲善其事,必先利其器,整理过往工作与生活中遇到的最好的工具软件 PDF合并等 PDF24 Tools PDF查看器 SumatraPDF 可以使用黑色来查看,相对不伤眼睛,也有电子书相关的阅读器 Kindle pdf裁边工具 briss 软件卸载…...
使用C#反射中的MAKEGENERICTYPE函数,来为泛型方法和泛型类指定(泛型的)类型
MakeGenericType 是一个在 C# 中用于创建开放类型的实例的方法。开放类型是一种未绑定类型参数的泛型类型。当你有一个泛型类型定义,并且想要用特定的类型实例化它时,你可以使用 MakeGenericType 方法。 public Type MakeGenericType (params Type[] ty…...
sql注入 (运用sqlmap解题)
注:level参数 使用–batch参数可指定payload测试复杂等级。共有五个级别,从1-5,默认值为1。等级越高,测试的payload越复杂,当使用默认等级注入不出来时,可以尝试使用–level来提高测试等级。 --level 参数决定了 sql…...
HTML5 Canvas 绘图教程二
在本教程中,我们将探讨 canvas 的高级用法,包括复杂的绘图 API、坐标系统和变换操作、平滑动画技术以及复杂应用和游戏开发的实践。 1. 绘图 API 高级方法 1.1 二次贝塞尔曲线 (quadraticCurveTo) 二次贝塞尔曲线需要两个点:一个控制点和一…...
Linux 命令 find 的深度解析与使用
Linux 命令 find 的深度解析与使用 在 Linux 系统中,find 命令是一个功能强大的工具,用于在文件系统中搜索文件或目录。无论是基于文件名、文件类型、文件大小、文件权限,还是基于文件的最后修改时间等,find 命令都能提供灵活的搜…...
字符串操作记录
1 拼接 Concat():拼接字符串 Let stringvalue “hello ”; Let result stringvalue.concat(“world”) Console.log(result) // “hello world” 2 删 Let stringvalue “hello world”Console.log(stringvalue.slice(3)); // ‘lo world’Console.log(stringvalue.subst…...
【python科学文献计量】关于中国知网检索策略的验证,以事故伤害严重程度检索为例
关于中国知网检索策略的验证,以事故伤害严重程度检索为例 1 背景2 文献下载3 数据处理1 背景 由于要进行相关研究内容的综述,需要了解当前我国对于事故伤害严重程度的研究现状,采用国内较为知名的检索网站(中国知网)进行文献数据集检索 由于最近知网出bug,检索的结果在…...
聊聊 Pulsar:Producer 源码解析
一、前言 Apache Pulsar 是一个企业级的开源分布式消息传递平台,以其高性能、可扩展性和存储计算分离架构在消息队列和流处理领域独树一帜。在 Pulsar 的核心架构中,Producer(生产者) 是连接客户端应用与消息队列的第一步。生产者…...
抖音增长新引擎:品融电商,一站式全案代运营领跑者
抖音增长新引擎:品融电商,一站式全案代运营领跑者 在抖音这个日活超7亿的流量汪洋中,品牌如何破浪前行?自建团队成本高、效果难控;碎片化运营又难成合力——这正是许多企业面临的增长困局。品融电商以「抖音全案代运营…...
基于数字孪生的水厂可视化平台建设:架构与实践
分享大纲: 1、数字孪生水厂可视化平台建设背景 2、数字孪生水厂可视化平台建设架构 3、数字孪生水厂可视化平台建设成效 近几年,数字孪生水厂的建设开展的如火如荼。作为提升水厂管理效率、优化资源的调度手段,基于数字孪生的水厂可视化平台的…...
《通信之道——从微积分到 5G》读书总结
第1章 绪 论 1.1 这是一本什么样的书 通信技术,说到底就是数学。 那些最基础、最本质的部分。 1.2 什么是通信 通信 发送方 接收方 承载信息的信号 解调出其中承载的信息 信息在发送方那里被加工成信号(调制) 把信息从信号中抽取出来&am…...
苍穹外卖--缓存菜品
1.问题说明 用户端小程序展示的菜品数据都是通过查询数据库获得,如果用户端访问量比较大,数据库访问压力随之增大 2.实现思路 通过Redis来缓存菜品数据,减少数据库查询操作。 缓存逻辑分析: ①每个分类下的菜品保持一份缓存数据…...
在Ubuntu中设置开机自动运行(sudo)指令的指南
在Ubuntu系统中,有时需要在系统启动时自动执行某些命令,特别是需要 sudo权限的指令。为了实现这一功能,可以使用多种方法,包括编写Systemd服务、配置 rc.local文件或使用 cron任务计划。本文将详细介绍这些方法,并提供…...
【C语言练习】080. 使用C语言实现简单的数据库操作
080. 使用C语言实现简单的数据库操作 080. 使用C语言实现简单的数据库操作使用原生APIODBC接口第三方库ORM框架文件模拟1. 安装SQLite2. 示例代码:使用SQLite创建数据库、表和插入数据3. 编译和运行4. 示例运行输出:5. 注意事项6. 总结080. 使用C语言实现简单的数据库操作 在…...
零基础设计模式——行为型模式 - 责任链模式
第四部分:行为型模式 - 责任链模式 (Chain of Responsibility Pattern) 欢迎来到行为型模式的学习!行为型模式关注对象之间的职责分配、算法封装和对象间的交互。我们将学习的第一个行为型模式是责任链模式。 核心思想:使多个对象都有机会处…...
如何在最短时间内提升打ctf(web)的水平?
刚刚刷完2遍 bugku 的 web 题,前来答题。 每个人对刷题理解是不同,有的人是看了writeup就等于刷了,有的人是收藏了writeup就等于刷了,有的人是跟着writeup做了一遍就等于刷了,还有的人是独立思考做了一遍就等于刷了。…...
今日学习:Spring线程池|并发修改异常|链路丢失|登录续期|VIP过期策略|数值类缓存
文章目录 优雅版线程池ThreadPoolTaskExecutor和ThreadPoolTaskExecutor的装饰器并发修改异常并发修改异常简介实现机制设计原因及意义 使用线程池造成的链路丢失问题线程池导致的链路丢失问题发生原因 常见解决方法更好的解决方法设计精妙之处 登录续期登录续期常见实现方式特…...
