当前位置: 首页 > news >正文

函数参数的最佳传递方式与现代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类获取资源的所有权,并在合适的时候处理它的释放。这是一种设计技术,例如,由 vectorunique_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中&#xff0c;如何最佳地传递函数参数以及如何处理类的特殊成员函数&#xff0c;一直是优化性能和代码质量的重要话题。下面我将详细解释这些概念。 使用移动语义实现 Swap 函数 移动语义&#xff08;Move Semantics&#xff09;能…...

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模型推理成本太大了…...

分享一下在微信小程序里怎么做一个投票链接

在当今信息化社会&#xff0c;投票已成为各行各业收集意见、汇聚智慧的重要手段。传统的投票方式往往需要投入大量人力物力&#xff0c;而如今&#xff0c;借助微信小程序&#xff0c;我们可以在几分钟内创建一个高效、便捷的投票平台。本文将详细介绍如何在微信小程序中添加投…...

v-model语法糖

v-model原理 v-model实现双向绑定的语法糖&#xff0c;常用于表单与组件之间的数据双向绑定v-model本质上是 value属性和input事件的一层包装 v-model的作用&#xff1a;提供数据的双向绑定数据发生了改变&#xff0c;页面会自动变 v-bind:value页面输入改变 &#xff0c; 数据…...

纷享销客荣获最佳制造业数字营销服务商奖

2023年10月26日&#xff0c;第二届中国制造业数智化发展大会在上海盛大召开。本次大会汇聚了制造行业的顶尖企业和专家&#xff0c;共同探讨如何通过数字化转型赋能企业自身成长&#xff0c;实现信息化向数字化的升级转型。 在本次盛会上&#xff0c;纷享销客以其卓越的基本面、…...

蓝桥杯每日一题2023.11.3

题目描述 承压计算 - 蓝桥云课 (lanqiao.cn) 题目分析 将重量存入a中&#xff0c;每一层从上到下进行计算&#xff0c;用d进行计算列的重量&#xff0c;当前d的重量应为正上数组和右上数组的个半和并加上自身的重量 计算到30层记录最大最小值&#xff0c;进行比例运算即可 …...

中国电子云-隐私计算-云原生安全可信计算,物理-硬件-系统-云产品-云平台,数据安全防护

目录 联邦学习的架构思想 中国电子云-隐私计算-云原生安全...

PHP服务器端电商API原理及示例讲解(电商接口开发/接入)

下面小编就为大家分享一篇PHP服务器端API原理及示例讲解(接口开发)&#xff0c;具有很好的参考价值&#xff0c;希望对大家有所帮助 相信大家都做过PHP请求电商API接口获取数据&#xff0c;比如淘宝平台商品API接口&#xff0c;订单接口&#xff0c;京东接口&#xff0c;1688接…...

Spring Cloud应用- Eureka原理、搭建

初期对Spring Cloud的学习以应用搭建为主&#xff0c;所以内容不会太枯燥。 一直以来&#xff0c;自以为Spring全家桶的学习中&#xff0c;Spring framework是基础中的基础&#xff0c;部分内容也还是必须要读源码去理解底层原理&#xff0c;SpringMVC、SpringBoot&#xff0c…...

Servlet 设置启动时机(web.xml方式和@WebServlet方式)

1、通过web.xml方式 5)Servlet的启动时机 - 默认情况下&#xff0c;servlet是不会随着容器的启动而被实例化的&#xff0c;只有当第一次给我发请求时才会被实例化那么&#xff0c;这种情况对于第一次请求是不公平的因此&#xff0c;为了提高用户体验度&#xff0c;提高服务器的…...

一个使用uniapp+vue3+ts+pinia+uview-plus开发小程序的基础模板

uniappuviewPlusvue3tspiniavite 开发基础模板 使用 uniapp vue3 ts pinia vite 开发基础模板&#xff0c;拿来即可使用&#xff0c;不要删除 yarn.lock 文件&#xff0c;否则会启动报错&#xff0c;这个可能和 pinia 的版本有关&#xff0c;所以不要随意修改。 拉取代码…...

Kali安装docker

第一步&#xff1a;kali添加Docker官方的GPG密钥 curl -fsSL https://download.docker.com/linux/debian/gpg | sudo apt-key add 第二步&#xff1a;进入root更新源&#xff1a; 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)是一种用于减少神经网络模型大小、减少计算量和提高推理效率的技术&#xff0c;通过去除神经…...

机器人仿真-gazebo学习笔记(3)URDF和机器人模型

1.URDF简介 URDF(统一机器人麦哦书格式)是ROS中的重要机器人模型描述格式&#xff0c;ROS提供了URDF文件的c解析器&#xff0c;可以解析URDF文件中使用XML格式的机器人模型。 urdf - ROS Wiki 自己查阅ros官方对URDF的介绍其实会强于大部分网上流传的文章。 1.URDF文件常用的…...

lua-resty-request库写入爬虫ip实现数据抓取

根据提供的引用内容&#xff0c;正确的库名称应该是lua-resty-http&#xff0c;而不是lua-resty-request。使用lua-resty-http库可以方便地进行爬虫&#xff0c;需要先安装OpenResty和lua-resty-http库&#xff0c;并将其引入到Lua脚本中。然后&#xff0c;可以使用lua-resty-h…...

gitlab Activating and deactivating users

原文&#xff1a;Redirecting... Deactivating a userActivating a user Activating and deactivating users GitLab 管理员可以停用和激活用户. Deactivating a user 在 GitLab 12.4 中引入 . 为了临时阻止没有最近活动的 GitLab 用户访问&#xff0c;管理员可以选择停用…...

linux入门到精通-第五章-动态库和静态库

目录 参考概述1、静态链接2 、动态链接3 、静态、动态编译对比 静态库和动态库简介传统编译 静态库制作和使用1、创建静态库的过程2、使用静态库 动态库制作和使用1、创建动态库的过程1&#xff09;、生成目标文件&#xff0c;此时要加编译选项&#xff1a;-fPIC &#xff08;f…...

markdown 如何更改字体以及颜色等功能

markdown 是IT人士写文档的常用方式&#xff0c;但是markdown默认又不支持颜色字体等特殊功能&#xff0c;所以呢想实现字体颜色高亮等特殊功能&#xff0c;实现的方法呢就是使用HTML&#xff0c;所以将部分文字改成HTML代码就行 颜色 <font color#0099ff>color #0099f…...

UE5 学习系列(二)用户操作界面及介绍

这篇博客是 UE5 学习系列博客的第二篇&#xff0c;在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下&#xff1a; 【Note】&#xff1a;如果你已经完成安装等操作&#xff0c;可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作&#xff0c;重…...

多云管理“拦路虎”:深入解析网络互联、身份同步与成本可视化的技术复杂度​

一、引言&#xff1a;多云环境的技术复杂性本质​​ 企业采用多云策略已从技术选型升维至生存刚需。当业务系统分散部署在多个云平台时&#xff0c;​​基础设施的技术债呈现指数级积累​​。网络连接、身份认证、成本管理这三大核心挑战相互嵌套&#xff1a;跨云网络构建数据…...

椭圆曲线密码学(ECC)

一、ECC算法概述 椭圆曲线密码学&#xff08;Elliptic Curve Cryptography&#xff09;是基于椭圆曲线数学理论的公钥密码系统&#xff0c;由Neal Koblitz和Victor Miller在1985年独立提出。相比RSA&#xff0c;ECC在相同安全强度下密钥更短&#xff08;256位ECC ≈ 3072位RSA…...

从WWDC看苹果产品发展的规律

WWDC 是苹果公司一年一度面向全球开发者的盛会&#xff0c;其主题演讲展现了苹果在产品设计、技术路线、用户体验和生态系统构建上的核心理念与演进脉络。我们借助 ChatGPT Deep Research 工具&#xff0c;对过去十年 WWDC 主题演讲内容进行了系统化分析&#xff0c;形成了这份…...

2024年赣州旅游投资集团社会招聘笔试真

2024年赣州旅游投资集团社会招聘笔试真 题 ( 满 分 1 0 0 分 时 间 1 2 0 分 钟 ) 一、单选题(每题只有一个正确答案,答错、不答或多答均不得分) 1.纪要的特点不包括()。 A.概括重点 B.指导传达 C. 客观纪实 D.有言必录 【答案】: D 2.1864年,()预言了电磁波的存在,并指出…...

Java多线程实现之Callable接口深度解析

Java多线程实现之Callable接口深度解析 一、Callable接口概述1.1 接口定义1.2 与Runnable接口的对比1.3 Future接口与FutureTask类 二、Callable接口的基本使用方法2.1 传统方式实现Callable接口2.2 使用Lambda表达式简化Callable实现2.3 使用FutureTask类执行Callable任务 三、…...

Frozen-Flask :将 Flask 应用“冻结”为静态文件

Frozen-Flask 是一个用于将 Flask 应用“冻结”为静态文件的 Python 扩展。它的核心用途是&#xff1a;将一个 Flask Web 应用生成成纯静态 HTML 文件&#xff0c;从而可以部署到静态网站托管服务上&#xff0c;如 GitHub Pages、Netlify 或任何支持静态文件的网站服务器。 &am…...

Spring Boot面试题精选汇总

&#x1f91f;致敬读者 &#x1f7e9;感谢阅读&#x1f7e6;笑口常开&#x1f7ea;生日快乐⬛早点睡觉 &#x1f4d8;博主相关 &#x1f7e7;博主信息&#x1f7e8;博客首页&#x1f7eb;专栏推荐&#x1f7e5;活动信息 文章目录 Spring Boot面试题精选汇总⚙️ **一、核心概…...

IoT/HCIP实验-3/LiteOS操作系统内核实验(任务、内存、信号量、CMSIS..)

文章目录 概述HelloWorld 工程C/C配置编译器主配置Makefile脚本烧录器主配置运行结果程序调用栈 任务管理实验实验结果osal 系统适配层osal_task_create 其他实验实验源码内存管理实验互斥锁实验信号量实验 CMISIS接口实验还是得JlINKCMSIS 简介LiteOS->CMSIS任务间消息交互…...

GC1808高性能24位立体声音频ADC芯片解析

1. 芯片概述 GC1808是一款24位立体声音频模数转换器&#xff08;ADC&#xff09;&#xff0c;支持8kHz~96kHz采样率&#xff0c;集成Δ-Σ调制器、数字抗混叠滤波器和高通滤波器&#xff0c;适用于高保真音频采集场景。 2. 核心特性 高精度&#xff1a;24位分辨率&#xff0c…...