C++理解临时对象的来源
当程序员之间进行交谈时,他们经常把仅仅需要一小段时间的变量称为临时变量。例如在下面这段swap(交换)例程里:
template<class T>
void swap(T& object1, T& object2)
{
T temp = object1;
object1 = object2;
object2 = temp;
}
通常把temp叫做临时变量。不过就C++而言,temp根本不是临时变量,它只是一个函数的局部对象。
在C++中真正的临时对象是看不见的,它们不出现在你的源代码中。建立一个没有命名的非堆(non-heap)对象会产生临时对象。这种未命名的对象通常在两种条件下产生:为了使函数成功调用而进行隐式类型转换和函数返回对象时。理解如何和为什么建立这些临时对象是很重要的,因为构造和释放它们的开销对于程序的性能来说有着不可忽视的影响。
首先考虑为使函数成功调用而建立临时对象这种情况。当传送给函数的对象类型与参数类型不匹配时会产生这种情况。例如一个函数,它用来计算一个字符在字符串中出现的次数:
// 返回ch在str中出现的次数
size_t countChar(const string& str, char ch);
char buffer[MAX_STRING_LEN];
char c;
// 读入到一个字符和字符串中,用setw
// 避免缓存溢出,当读取一个字符串时
cin >> c >> setw(MAX_STRING_LEN) >> buffer;
cout << "There are " << countChar(buffer, c)
<< " occurrences of the character " << c
<< " in " << buffer << endl;
看一下countChar的调用。第一个被传送的参数是字符数组,但是对应函数的正被绑定的参数的类型是const string&。仅当消除类型不匹配后,才能成功进行这个调用,你的编译器很乐意替你消除它,方法是建立一个string类型的临时对象。通过以buffer做为参数调用string的构造函数来初始化这个临时对象。countChar的参数str被绑定在这个临时的string对象上。当countChar返回时,临时对象自动释放。
这样的类型转换很方便(尽管很危险-参见条款M5),但是从效率的观点来看,临时string对象的构造和释放是不必要的开销。通常有两个方法可以消除它。一种是重新设计你的代码,不让发生这种类型转换。这种方法在条款M5中被研究和分析。另一种方法是通过修改软件而不再需要类型转换,条款M21讲述了如何去做。
仅当通过传值(by value)方式传递对象或传递常量引用(reference-to-const)参数时,才会发生这些类型转换。当传递一个非常量引用(reference-to-non-const)参数对象,就不会发生。考虑一下这个函数:
void uppercasify(string& str); // 把str中所有的字符
// 改变成大写
在字符计数的例子里,能够成功传递char数组到countChar中,但是在这里试图用char数组调用upeercasify函数,则不会成功:
char subtleBookPlug[] = "Effective C++";
uppercasify(subtleBookPlug); // 错误!
没有为使调用成功而建立临时对象,为什么呢?
假设建立一个临时对象,那么临时对象将被传递到upeercasify中,其会修改这个临时对象,把它的字符改成大写。但是对subtleBookPlug函数调用的真正参数没有任何影响;仅仅改变了临时从subtleBookPlug生成的string对象。无疑这不是程序员所希望的。程序员传递subtleBookPlug参数到uppercasify函数中,期望修改subtleBookPlug的值。当程序员期望修改非临时对象时,对非常量引用(references-to-non-const)进行的隐式类型转换却修改临时对象。这就是为什么C++语言禁止为非常量引用(reference-to-non-const)产生临时对象。这样非常量引用(reference-to-non-const)参数就不会遇到这种问题。
建立临时对象的第二种环境是函数返回对象时。例如operator+必须返回一个对象,以表示它的两个操作数的和(参见Effective C++ 条款23)。例如给定一个类型Number,这种类型的operator+被这样声明:
const Number operator+(const Number& lhs,
const Number& rhs);
这个函数的返回值是临时的,因为它没有被命名;它只是函数的返回值。你必须为每次调用operator+构造和释放这个对象而付出代价。(有关为什么返回值是const的详细解释,参见Effective C++条款21)
通常你不想付出这样的开销。对于这种函数,你可以切换到operator=,而避免开销。条款M22告诉我们进行这种转换的方法。不过对于大多数返回对象的函数来说,无法切换到不同的函数,从而没有办法避免构造和释放返回值。至少在概念上没有办法避免它。然而概念和现实之间又一个黑暗地带,叫做优化,有时你能以某种方法编写返回对象的函数,以允许你的编译器优化临时对象。这些优化中,最常见和最有效的是返回值优化,这是条款M20的内容。
综上所述,临时对象是有开销的,所以你应该尽可能地去除它们,然而更重要的是训练自己寻找可能建立临时对象的地方。在任何时候只要见到常量引用(reference-to-const)参数,就存在建立临时对象而绑定在参数上的可能性。在任何时候只要见到函数返回对象,就会有一个临时对象被建立(以后被释放)。学会寻找这些对象构造,你就能显著地增强透过编译器表面动作而看到其背后开销的能力。
相关文章:
C++理解临时对象的来源
当程序员之间进行交谈时,他们经常把仅仅需要一小段时间的变量称为临时变量。例如在下面这段swap(交换)例程里: template<class T> void swap(T& object1, T& object2) { T temp object1; object1 object2; object2 temp; } 通常把t…...
C++协助完成返回值优化
一个返回对象的函数很难有较高的效率,因为传值返回会导致调用对象内的构造和析构函数(参见条款M19),这种调用是不能避免的。问题很简单:一个函数要么为了保证正确的行为而返回对象要么就不这么做。如果它返回了对象,就没有办法摆脱…...
2024年睿抗机器人开发者大赛(RAICOM)国赛题解
目录 RC-u1 大家一起查作弊 分数 15 RC-u2 谁进线下了?II 分数 20 RC-u3 势均力敌 分数 25 RC-u4 City 不 City 分数 30 RC-u5 贪心消消乐 分数 30 RC-u1 大家一起查作弊 分数 15 简单模拟题,对于多行读入使用while(getline(cin…...

声明式UI语法
一、ArkTS的基本组成 Entry // 装饰器 Component // 装饰器 struct Hello { // 自定义组件State myText: string World;build() { // UI描述Column() { // 系统组件Text(Hello ${this.myText}).fontSize(50)Divider()Button(Click me).onClick(() > { // 事件方法t…...
JDBC连接数和1521连接数之间的区别和联系(Java Database Connectivity)
JDBC(Java Database Connectivity)连接数和1521连接数之间的区别和联系如下: 区别 概念不同: JDBC连接数:指通过JDBC技术建立的数据库连接数。JDBC是Java中的一套API,用于连接和操作关系数据库。JDBC连接数…...

Leetcode - 136双周赛
目录 一,3238. 求出胜利玩家的数目 二,3239. 最少翻转次数使二进制矩阵回文 I 三,3240. 最少翻转次数使二进制矩阵回文 II 四,3241. 标记所有节点需要的时间 一,3238. 求出胜利玩家的数目 本题直接暴力求解&#x…...
SQLite ORDER BY 语句
SQLite ORDER BY 语句 SQLite 的 ORDER BY 语句用于对查询结果进行排序。排序可以是升序(ASC)或降序(DESC)。默认情况下,如果不指定排序方式,ORDER BY 会以升序对结果进行排序。 语法 SQLite ORDER BY 语…...
MTK Android12 系统中应用加载 .so 文件的问题分析
在本篇博客中,我将详细总结在 Android 12 系统上进行的几个实验,包括如何加载自定义 JAR 文件、如何解压和确认 .so 文件,以及如何验证系统报错提示。本文将介绍使用 PathClassLoader 和 DexClassLoader 动态加载类的实验,分析系统报错信息,并最终得出结论。 推荐:《Andr…...

bpmn简单使用(制作流程图)
1、先下载依赖,下面是我下载的版本 "bpmn-io/properties-panel": "^3.23.0", "bpmn-js": "^17.9.1", "bpmn-js-properties-panel": "^5.6.1", "camunda-bpmn-moddle": "^7.0.1",…...
【算法模板】算竞技巧:Python对拍数据生成
在计算机编程竞赛中,对拍(Testlib)是一种验证程序正确性的方法。它通常用于检查一个程序的输出是否与另一个程序的输出一致,以确保程序的正确性。 对拍程序 【算法模板】算竞技巧:对拍全解_算法竞赛对拍-CSDN博客 #i…...

计算机基本理论与程序运行原理概述
目录 计算机的基本表示方法 计算机的组成 程序运行的原理 指令执行的流水线 编译原理 个人理解 面试题总结 计算机的基本表示方法 计算机系统使用高、低电平来表示逻辑1和0。数据在计算机中的存储、传输和处理均以二进制形式进行。数据通过总线作为电信号进行传输&…...

SpringBoot中的server.context-path
目录 一、问题引入 二、代码片段展示 2.1.接口层 2.2.application.properties 三、问题分析 3.1.server.context-path 作用 3.2.正确展示 四、HTTP请求响应码简介 4.1.响应码参考来源 4.2.源码示例 4.2.1.源码总述 4.2.2.正常情况——2XX: generally "OK&…...

AI绘画绘画 Stable Diffusion ,从零开始轻松变现,AI绘画副业创收指南,一天一个AI帮你赚钱小技巧!
大家好,我是灵魂画师向阳 通过长达几个月的AI绘画Stable Diffusion 系统教程,相信大家已经对AI绘画有了一个大概的认知。最近就有很多粉丝总是问我,AI绘画学会后如何进行变现,或者是做副业呢? 那今天我就分享一些目前…...

阿里云镜像站,提供了各种第三方镜像地址
阿里云提供了各项镜像缓存地址,对于很多国外服务的地址,通过阿里云缓存的地址去下载,速度会非常快。 如下,打开阿里云官方网站: 进入“镜像站”,如下图所示: 有我们常用的 npm、maven、操作系统…...

stm32入门学习11-硬件I2C和MPU
(一)I2C硬件电路 stm32内部有I2C的硬件电路,我们可以使用stm32的标准库函数来实现I2C,这可以为我们减少对软件资源的占用 I2C硬件电路常用的标准库函数 void I2C_Init(I2C_TypeDef* I2Cx, I2C_InitTypeDef* I2C_InitStruct); /…...
如何在C++、PHP、GO中使用AI生成PPT API接口
在当今快节奏的商业环境中,演示文稿的制作不仅需要快速,还需要具有吸引力和专业性。AI生成PPT API 服务提供了一种创新的解决方案,能够根据用户提供的内容自动生成演示文稿,极大地提高了效率和质量。本文将详细介绍AI生成PPT的优势…...

力扣面试150 逆波兰表达式求值 栈 模拟栈
Problem: 150. 逆波兰表达式求值 👨🏫 参考题解 class Solution {//纯数组模拟栈实现(推荐) 3 ms 36 MBpublic static int evalRPN(String[] tokens) {int[] numStack new int[tokens.length / 2 1];int index 0;for (String s : tokens) {swit…...

动手学深度学习V2每日笔记(深度卷积神经网络AlexNet)
本文主要参考沐神的视频教程 https://www.bilibili.com/video/BV1h54y1L7oe/spm_id_from333.788.recommend_more_video.0&vd_sourcec7bfc6ce0ea0cbe43aa288ba2713e56d 文档教程 https://zh-v2.d2l.ai/ 本文的主要内容对沐神提供的代码中个人不太理解的内容进行笔记记录&…...
室内定位:紧耦合的学习惯性里程 (TLIO)
a### TLIO论文解读:紧耦合的学习惯性测程 (TLIO) 在惯性测量单元 (IMU) 领域,如何在短时间内精确地估计位置和姿态一直是一个挑战。最近,论文《TLIO: Tight Learned Inertial Odometry》提出了一种创新的方法,通过将深度学习与扩展卡尔曼滤波器 (EKF) 紧密结合,来解决这一…...
【面试之算法篇】寻找二叉树中两个节点的最低公共祖先
题目 给定一个树的根节点root和两个子节点a,b,返回二叉树中两个节点的最低公共祖先。二叉树每个节点的值都是不同的整数 10060 12040 null 4 74和7的最低公共祖先是120,60和40的最低公共祖先是60 思路 两个节点的祖先会有多个,只有是祖先的节点才有可能会是最低公共…...

第19节 Node.js Express 框架
Express 是一个为Node.js设计的web开发框架,它基于nodejs平台。 Express 简介 Express是一个简洁而灵活的node.js Web应用框架, 提供了一系列强大特性帮助你创建各种Web应用,和丰富的HTTP工具。 使用Express可以快速地搭建一个完整功能的网站。 Expre…...

测试微信模版消息推送
进入“开发接口管理”--“公众平台测试账号”,无需申请公众账号、可在测试账号中体验并测试微信公众平台所有高级接口。 获取access_token: 自定义模版消息: 关注测试号:扫二维码关注测试号。 发送模版消息: import requests da…...
Oracle查询表空间大小
1 查询数据库中所有的表空间以及表空间所占空间的大小 SELECTtablespace_name,sum( bytes ) / 1024 / 1024 FROMdba_data_files GROUP BYtablespace_name; 2 Oracle查询表空间大小及每个表所占空间的大小 SELECTtablespace_name,file_id,file_name,round( bytes / ( 1024 …...

【JVM】- 内存结构
引言 JVM:Java Virtual Machine 定义:Java虚拟机,Java二进制字节码的运行环境好处: 一次编写,到处运行自动内存管理,垃圾回收的功能数组下标越界检查(会抛异常,不会覆盖到其他代码…...
LLM基础1_语言模型如何处理文本
基于GitHub项目:https://github.com/datawhalechina/llms-from-scratch-cn 工具介绍 tiktoken:OpenAI开发的专业"分词器" torch:Facebook开发的强力计算引擎,相当于超级计算器 理解词嵌入:给词语画"…...

中医有效性探讨
文章目录 西医是如何发展到以生物化学为药理基础的现代医学?传统医学奠基期(远古 - 17 世纪)近代医学转型期(17 世纪 - 19 世纪末)现代医学成熟期(20世纪至今) 中医的源远流长和一脉相承远古至…...
《C++ 模板》
目录 函数模板 类模板 非类型模板参数 模板特化 函数模板特化 类模板的特化 模板,就像一个模具,里面可以将不同类型的材料做成一个形状,其分为函数模板和类模板。 函数模板 函数模板可以简化函数重载的代码。格式:templa…...
PAN/FPN
import torch import torch.nn as nn import torch.nn.functional as F import mathclass LowResQueryHighResKVAttention(nn.Module):"""方案 1: 低分辨率特征 (Query) 查询高分辨率特征 (Key, Value).输出分辨率与低分辨率输入相同。"""def __…...

如何更改默认 Crontab 编辑器 ?
在 Linux 领域中,crontab 是您可能经常遇到的一个术语。这个实用程序在类 unix 操作系统上可用,用于调度在预定义时间和间隔自动执行的任务。这对管理员和高级用户非常有益,允许他们自动执行各种系统任务。 编辑 Crontab 文件通常使用文本编…...
省略号和可变参数模板
本文主要介绍如何展开可变参数的参数包 1.C语言的va_list展开可变参数 #include <iostream> #include <cstdarg>void printNumbers(int count, ...) {// 声明va_list类型的变量va_list args;// 使用va_start将可变参数写入变量argsva_start(args, count);for (in…...