函数参数的最佳传递方式与现代C++的规则
函数参数的最佳传递方式与现代C++的规则
在C++中,如何最佳地传递函数参数以及如何处理类的特殊成员函数,一直是优化性能和代码质量的重要话题。下面我将详细解释这些概念。
使用移动语义实现 Swap 函数
移动语义(Move Semantics)能够提升性能的一个例子是实现一个交换(swap)函数模板,该模板交换两个对象。不使用移动语义的实现如下:
template <typename T>
void swapCopy(T& a, T& b) {T temp { a };a = b;b = temp;
}
这种实现方式会影响性能,尤其是当类型T的拷贝开销很大时。使用移动语义,实现可以避免所有拷贝:
template <typename T>
void swapMove(T& a, T& b) {T temp { std::move(a) };a = std::move(b);b = std::move(temp);
}
这就是标准库中 std::swap() 的实现方式。
在返回语句中使用 std::move()
如果返回语句的形式为 return object;,并且 object 是一个局部变量、函数参数或临时值,编译器会将其视为右值表达式,并触发返回值优化(RVO)。此外,如果 object 是一个局部变量,命名返回值优化(NRVO)也可能发生。RVO和NRVO都是拷贝省略(Copy Elision)的形式,使得从函数返回对象非常高效。
使用 std::move() 来返回对象会怎样呢?无论你写 return object; 还是 return std::move(object);,在两种情况下,编译器都会将其视为右值表达式。然而,使用 std::move(),编译器无法再应用RVO或NRVO,这可能会对性能产生重大影响!
所以,请记住以下规则:当从函数返回局部变量或参数时,只需写 return object;,不要使用 std::move()。
参数的最佳传递方式
到目前为止,建议对非原始类型的函数参数使用 const 引用参数,以避免不必要的昂贵拷贝。然而,随着右值的引入,情况略有变化。想象一个无论如何都会拷贝其参数的函数。现在,你可能想要添加一个重载,以避免在右值的情况下进行任何拷贝。这里有一个例子:
class DataHolder {
public:void setData(const std::vector<int>& data) {m_data = data;}void setData(std::vector<int>&& data) {m_data = std::move(data);}private:std::vector<int> m_data;
};
但是,有一种更好的方式,涉及使用传值的单个方法。对于函数本来就会拷贝的参数,使用传值语义是最优的选择。如果传入左值,它恰好被拷贝一次。如果传入右值,不会进行拷贝。
零规则(Rule of Zero)
在现代C++中,应该遵循所谓的零规则(Rule of Zero)。这个规则指出,你应该设计你的类,使它们不需要任何特殊的成员函数。怎么做到这一点呢?基本上,你应该避免使用任何老式的动态分配内存。相反,应该使用像标准库容器这样的现代构造。例如,使用 vector<vector<SpreadsheetCell>> 替代 Spreadsheet 类中的 SpreadsheetCell** 数据成员。vector 会自动处理内存,因此不需要任何特殊的成员函数。
现代C++中推荐使用零规则,而五规则(Rule of Five)应该限于自定义的资源获取是初始化(RAII)类。RAII类获取资源的所有权,并在合适的时候处理它的释放。这是一种设计技术,例如,由 vector 和 unique_ptr 使用,并在后续的章节中进一步讨论。
静态方法和 const 方法是 C++ 中的两个重要概念,它们各自在不同的情况下发挥着重要作用。
静态方法(Static Methods)
静态方法是那些不依赖于类的实例而存在的方法。与静态数据成员类似,静态方法适用于整个类,而不是每个对象。在实现静态方法时,需要注意以下几点:
- 静态方法不是针对特定对象调用的,因此它们没有
this指针,也无法访问类的非静态成员。 - 静态方法可以访问类的私有和保护的静态成员,也可以在具有相同类型的对象上访问私有和保护的非静态成员,前提是这些对象对静态方法可见(例如,通过作为参数传递对象的引用或指针)。
- 在类内部的任何方法中,可以像调用常规成员函数一样调用静态方法。在类外部,需要使用作用域解析操作符(
::)并带上类名来调用静态方法。
例如:
Foo::bar();
const 方法(Const Methods)
const 方法是保证不会修改任何数据成员的方法。如果你有一个 const 对象,引用到 const 或指向 const 的指针,编译器不允许你调用除非是 const 方法的任何方法。通过在方法声明时使用 const 关键字,可以保证该方法不会修改任何数据成员。
例如:
double SpreadsheetCell::getValue() const {return m_value;
}std::string SpreadsheetCell::getString() const {return doubleToString(m_value);
}
- 在
const方法内部,所有数据成员都被视为const,因此如果尝试修改数据成员,编译器会报错。 - 不能将静态方法声明为
const,因为这是多余的。静态方法没有类的实例,因此它们无法更改内部值。 - 在非
const对象上可以调用const和非const方法。然而,只能在const对象上调用const方法。
mutable 数据成员(Mutable Data Members)
有时,你可能会编写一个在逻辑上是 const 的方法,但该方法恰好会更改对象的某个数据成员。这种修改对用户可见的数据没有影响,但从技术上讲是一种更改,因此编译器不允许你将方法声明为 const。在这种情况下,可以使用 mutable 关键字来声明那些即使在 const 方法中也可以被修改的数据成员。
例如:
class SpreadsheetCell {// ...
private:double m_value { 0 };mutable size_t m_numAccesses { 0 };// ...
};double SpreadsheetCell::getValue() const {m_numAccesses++;return m_value;
}std::string SpreadsheetCell::getString() const {m_numAccesses++;return doubleToString(m_value);
}
在这个例子中,即使 getValue() 和 getString() 被标记为 const,它们也可以修改 m_numAccesses,因为它被声明为 mutable。这允许方法在保持其 const 性质的同时,对某些数据成员进行修改。
参考:Professional C++ 5Th Edition
公众号:coding日记
相关文章:
函数参数的最佳传递方式与现代C++的规则
函数参数的最佳传递方式与现代C的规则 在C中,如何最佳地传递函数参数以及如何处理类的特殊成员函数,一直是优化性能和代码质量的重要话题。下面我将详细解释这些概念。 使用移动语义实现 Swap 函数 移动语义(Move Semantics)能…...
Asterisk Ubuntu 安装
更新环境 sudo apt update sudo apt install wget build-essential git autoconf subversion pkg-config libtool sudo contrib/scripts/get_mp3_source.sh A addons/mp3 A addons/mp3/common.c A addons/mp3/huffman.h A addons/mp3/tabinit.c A addons/mp3/Ma…...
rwkv模型lora微调之accelerate和deepspeed训练加速
目录 一、rwkv模型简介 二、lora原理简介 三、rwkv-lora微调 1、数据整理 2、环境搭建 a、Dockerfile编写 b、制造镜像 c、容器启动 3、训练代码修改 四、模型推理 1、模型推理 2、lora权重合并 3、推理web服务 五、总结 由于业务采用的ChatGLM模型推理成本太大了…...
分享一下在微信小程序里怎么做一个投票链接
在当今信息化社会,投票已成为各行各业收集意见、汇聚智慧的重要手段。传统的投票方式往往需要投入大量人力物力,而如今,借助微信小程序,我们可以在几分钟内创建一个高效、便捷的投票平台。本文将详细介绍如何在微信小程序中添加投…...
v-model语法糖
v-model原理 v-model实现双向绑定的语法糖,常用于表单与组件之间的数据双向绑定v-model本质上是 value属性和input事件的一层包装 v-model的作用:提供数据的双向绑定数据发生了改变,页面会自动变 v-bind:value页面输入改变 , 数据…...
纷享销客荣获最佳制造业数字营销服务商奖
2023年10月26日,第二届中国制造业数智化发展大会在上海盛大召开。本次大会汇聚了制造行业的顶尖企业和专家,共同探讨如何通过数字化转型赋能企业自身成长,实现信息化向数字化的升级转型。 在本次盛会上,纷享销客以其卓越的基本面、…...
蓝桥杯每日一题2023.11.3
题目描述 承压计算 - 蓝桥云课 (lanqiao.cn) 题目分析 将重量存入a中,每一层从上到下进行计算,用d进行计算列的重量,当前d的重量应为正上数组和右上数组的个半和并加上自身的重量 计算到30层记录最大最小值,进行比例运算即可 …...
中国电子云-隐私计算-云原生安全可信计算,物理-硬件-系统-云产品-云平台,数据安全防护
目录 联邦学习的架构思想 中国电子云-隐私计算-云原生安全...
PHP服务器端电商API原理及示例讲解(电商接口开发/接入)
下面小编就为大家分享一篇PHP服务器端API原理及示例讲解(接口开发),具有很好的参考价值,希望对大家有所帮助 相信大家都做过PHP请求电商API接口获取数据,比如淘宝平台商品API接口,订单接口,京东接口,1688接…...
Spring Cloud应用- Eureka原理、搭建
初期对Spring Cloud的学习以应用搭建为主,所以内容不会太枯燥。 一直以来,自以为Spring全家桶的学习中,Spring framework是基础中的基础,部分内容也还是必须要读源码去理解底层原理,SpringMVC、SpringBoot,…...
Servlet 设置启动时机(web.xml方式和@WebServlet方式)
1、通过web.xml方式 5)Servlet的启动时机 - 默认情况下,servlet是不会随着容器的启动而被实例化的,只有当第一次给我发请求时才会被实例化那么,这种情况对于第一次请求是不公平的因此,为了提高用户体验度,提高服务器的…...
一个使用uniapp+vue3+ts+pinia+uview-plus开发小程序的基础模板
uniappuviewPlusvue3tspiniavite 开发基础模板 使用 uniapp vue3 ts pinia vite 开发基础模板,拿来即可使用,不要删除 yarn.lock 文件,否则会启动报错,这个可能和 pinia 的版本有关,所以不要随意修改。 拉取代码…...
Kali安装docker
第一步:kali添加Docker官方的GPG密钥 curl -fsSL https://download.docker.com/linux/debian/gpg | sudo apt-key add 第二步:进入root更新源: su rootecho ‘deb https://download.docker.com/linux/debian stretch stable’> /etc/ap…...
Maven第七章:Maven工程最佳实践
Maven第七章:Maven工程最佳实践 前言 本章重点,通过一个maven工程最佳实践案例,熟悉和掌握maven在项目中的应用基本思路,让你的技能值瞬间暴涨。 最佳实践 确定项目的坐标和依赖 在Maven中,项目的坐标定义了项目的唯一标识符,包括groupId、artifactId和version。因此,在…...
【深度学习】【pytorch】对卷积层置零卷积核进行真实剪枝
最近需要对深度学习模型进行部署,因此需要对模型进行压缩,博主取舍了很多大佬的博文并亲测有效,分享笔记邀大家共同学习讨论 文章目录 前言卷积层剪枝总结 前言 深度学习剪枝(Pruning)是一种用于减少神经网络模型大小、减少计算量和提高推理效率的技术,通过去除神经…...
机器人仿真-gazebo学习笔记(3)URDF和机器人模型
1.URDF简介 URDF(统一机器人麦哦书格式)是ROS中的重要机器人模型描述格式,ROS提供了URDF文件的c解析器,可以解析URDF文件中使用XML格式的机器人模型。 urdf - ROS Wiki 自己查阅ros官方对URDF的介绍其实会强于大部分网上流传的文章。 1.URDF文件常用的…...
lua-resty-request库写入爬虫ip实现数据抓取
根据提供的引用内容,正确的库名称应该是lua-resty-http,而不是lua-resty-request。使用lua-resty-http库可以方便地进行爬虫,需要先安装OpenResty和lua-resty-http库,并将其引入到Lua脚本中。然后,可以使用lua-resty-h…...
gitlab Activating and deactivating users
原文:Redirecting... Deactivating a userActivating a user Activating and deactivating users GitLab 管理员可以停用和激活用户. Deactivating a user 在 GitLab 12.4 中引入 . 为了临时阻止没有最近活动的 GitLab 用户访问,管理员可以选择停用…...
linux入门到精通-第五章-动态库和静态库
目录 参考概述1、静态链接2 、动态链接3 、静态、动态编译对比 静态库和动态库简介传统编译 静态库制作和使用1、创建静态库的过程2、使用静态库 动态库制作和使用1、创建动态库的过程1)、生成目标文件,此时要加编译选项:-fPIC (f…...
markdown 如何更改字体以及颜色等功能
markdown 是IT人士写文档的常用方式,但是markdown默认又不支持颜色字体等特殊功能,所以呢想实现字体颜色高亮等特殊功能,实现的方法呢就是使用HTML,所以将部分文字改成HTML代码就行 颜色 <font color#0099ff>color #0099f…...
从蓝牙时钟到通用Timer:详解非32位满量程下的时间回环处理技巧
从蓝牙时钟到通用Timer:非标准位宽下的时间回环处理实战指南 在嵌入式系统中,时间管理如同隐形的骨架,支撑着各类关键功能的稳定运行。当开发者从32位通用定时器转向蓝牙协议栈中的28位时钟,或面对某些硬件平台上的24位专用定时器…...
Input Leap终极指南:3步实现跨设备键盘鼠标无缝共享
Input Leap终极指南:3步实现跨设备键盘鼠标无缝共享 【免费下载链接】input-leap Open-source KVM software 项目地址: https://gitcode.com/gh_mirrors/in/input-leap 你是否厌倦了在多台电脑之间频繁切换键盘和鼠标?Input Leap跨设备控制功能正…...
Arduino与树莓派协同开发:通信协议、实战项目与物联网应用
1. 项目概述:当开源硬件“大脑”遇上“小脑”如果你玩过乐高,大概能理解那种把不同功能的模块拼装起来,实现一个有趣功能的乐趣。在开源硬件的世界里,Arduino Uno和Raspberry Pi(树莓派)系列,就…...
Prettier配置踩坑实录:我的‘singleQuote: true’为什么不生效?深度解析VSCode格式化优先级与冲突解决
Prettier配置失效深度解析:VSCode格式化优先级与冲突解决实战 当你满怀期待地在.prettierrc中写下"singleQuote": true,保存文件后按下格式化快捷键——却发现引号依然顽固地保持双引号。这不是个例,而是前端开发者每天都会遇到的配…...
PMP认证深度解析:从知识体系到实战应用的全方位指南
1. 项目概述:从“认证”到“职业语言”的深度解码当你在项目管理圈子里待久了,会发现一个有趣的现象:无论大家来自哪个行业——是互联网大厂的产品研发,还是传统制造业的产线升级,甚至是大型活动的策划执行——只要聊到…...
社会风气何以如此?渡劫未彻底,继续渡劫。从为人民服务到为节点服务
社会风气何以如此?渡劫未彻底,继续渡劫。从为人民服务到为节点服务。 Jianbing Zhu 1 1 ECT-OS-JiuHuaShan 文明实践室 ORCID: 0009-0006-8591-1891 DOI: 10.5281/zenodo.20302480 Email: ect-os-jiuhuashanzohomail.cn 预印本提交:202…...
YOLOv8实时目标检测与自适应控制技术在游戏辅助系统中的应用研究
YOLOv8实时目标检测与自适应控制技术在游戏辅助系统中的应用研究 【免费下载链接】RookieAI_yolov8 基于yolov8实现的AI自瞄项目 AI self-aiming project based on yolov8 项目地址: https://gitcode.com/gh_mirrors/ro/RookieAI_yolov8 技术挑战剖析:实时游…...
为什么92%的研究者搜不到关键书评?Perplexity图书评论搜索的3大认知盲区与实时校准方案
更多请点击: https://codechina.net 第一章:为什么92%的研究者搜不到关键书评? 学术资源检索的失效,往往并非源于信息缺失,而是检索逻辑与出版生态的错位。当前主流学术数据库(如Google Scholar、CNKI、JS…...
macOS用户必备:3步解决QQ音乐加密格式的终极转换方案
macOS用户必备:3步解决QQ音乐加密格式的终极转换方案 【免费下载链接】QMCDecode QQ音乐QMC格式转换为普通格式(qmcflac转flac,qmc0,qmc3转mp3, mflac,mflac0等转flac),仅支持macOS,可自动识别到QQ音乐下载目录,默认转…...
3分钟学会在Windows上安装安卓应用:APK-Installer完整指南
3分钟学会在Windows上安装安卓应用:APK-Installer完整指南 【免费下载链接】APK-Installer An Android Application Installer for Windows 项目地址: https://gitcode.com/GitHub_Trending/ap/APK-Installer 想在Windows电脑上直接运行安卓应用,…...
