函数参数的最佳传递方式与现代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日记

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数据库概述 -- 数据模型知识点要点详解

数据模型 概述概念数据特征组成要素分类概念层数据模型逻辑层数据模型物理层数据模型 主页传送门&#xff1a;&#x1f4c0; 传送 概述 数据模型是对现实世界数据特征的抽象&#xff0c;它描述了数据的结构、操作和约束条件&#xff0c;为数据库系统的信息表示与操作提供一个抽…

JWT

目录 JWT组成 第一部分header 第二部分payload 第三部分signature 注意 JWT认证算法&#xff1a;签发和校验 drf使用jwt drf项目的jwt认证开发流程 drf-jwt安装和简单使用 安装 简单使用 drf-jwt使用 jwt内置类JSONWebTokenAuthentication 控制使用jwt的登录接口…

【计算机网络】计算机网络和因特网

一.基本术语介绍 端系统通过通信链路&#xff08;communication link&#xff09;和分组交换机&#xff08;packet switch&#xff09;连接到一起&#xff0c;连接这些端系统和分组交换机的物理媒体包括&#xff1a;同轴电缆&#xff0c;铜线&#xff0c;光纤和无线电频谱。而…

人工智能基础_机器学习014_BGD批量梯度下降公式更新_进一步推导_SGD随机梯度下降和MBGD小批量梯度下降公式进一步推导---人工智能工作笔记0054

然后我们先来看BGD批量梯度下降,可以看到这里,其实这个公式来源于 梯度下降的公式对吧,其实就是对原始梯度下降公式求偏导以后的梯度下降公式,然后 使用所有样本进行梯度下降得来的,可以看到* 1/n 其实就是求了一个平均数对吧.所有样本的平均数. 然后我们看,我们这里* 1/n那么…

Istio实战(十二)-Istio 延长自签发证书的有效期

因为历史原因,Istio 的自签发证书只有一年的有效期。如果你选择使用 Istio 的自签发证书,就需要在它们过期之前订好计划进行根证书的更迭。根证书过期可能会导致集群范围内的意外中断。 我们认为每年更换根证书和密钥是一个安全方面的最佳实践,我们会在后续内容中介绍如何完…

启用NTP服务解决Linux系统时间与北京时间不同步问题

一、背景 1、服务器的Linux版本为Linux version 4.18.0-348.7.1.el8_5.x86_64 (mockbuildkbuilder.bsys.centos.org) (gcc version 8.5.0 20210514 (Red Hat 8.5.0-4) (GCC)) #1 SMP Wed Dec 22 13:25:12 UTC 2021 2、NTP即Network Time Protocol&#xff08;网络时间协议&am…

webpack 与 grunt、gulp 的不同?

结论先行&#xff1a; Webpack、Grunt 和 Gulp 都是前端开发中常用的构建工具&#xff0c;但是 Webpack 是基于模块化打包的工具&#xff0c;并支持模块化开发。而 Grunt 和 Gulp 都是基于任务的构建工具&#xff0c;自动执行指定的任务&#xff0c;但不支持模块化开发。 1、相…

JavaScript设计模式之适配器模式

一般为了解决不兼容的问题&#xff0c;把一个类的接口换成我们想要的接口&#xff0c;类似于转换器。 举个例子&#xff1a; 我想听歌的时候&#xff0c;我发现我没带耳机&#xff0c;我的手机是 iphone 的&#xff0c;而现在我只有一个 Type-C 的耳机&#xff0c;为了能够听歌…

Unity3D与iOS的交互 简单版开箱即用

本文适合的情况如下&#xff1a; Unity客户端人员 与 IOS端研发人员合作的情况 目录 From U3D to iOS 实现原理 1.unity工程目录创建2个文件 NativeCallProxy.m、NativeCallProxy.h 并且放到Unity工程目录Plugins/iOS/unity_ios_plus目录下 2.创建C#调用脚本 定义对应.mm脚…

sql常用语句笔记

增&#xff1a;INSERT INTO <表名> &#xff08;列名&#xff09;VALUES (值) (1)增加&#xff1a; 新增 INSERT INTO 表名 &#xff08;列&#xff09;values (值)&#xff0c;值一一对应列的位置&#xff0c;没写的列值会自动填入null或默认值 eg: INSERT INTO student…

海康监控摄像机和录像机接入LiveMedia GB28181平台实现远程调取监控视频

海康威视各种型号监控摄像头或硬盘录像机&#xff08;NVR/HVR&#xff09;接入LiveMedia GB28181平台配置过程都非常简单明了&#xff0c;但有些细节需要注意&#xff0c;避免走弯路。 1、基本要求 (1) 网络要求 总体来说&#xff0c;只要监控设备和GB28181平台的网络是连通…

centos9 stream 下 rabbitmq高可用集群搭建及使用

RabbitMQ是一种常用的消息队列系统&#xff0c;可以快速搭建一个高可用的集群环境&#xff0c;以提高系统的弹性和可靠性。下面是搭建RabbitMQ集群的步骤&#xff1a; 基于centos9 stream系统 1. 安装Erlang和RabbitMQ 首先需要在所有节点上安装Erlang和RabbitMQ。建议使用官…

7个UI设计必备课程,小白必看!

无论你是想提高技能的资深UI设计师还是网站开发人员&#xff0c;又或者是刚转行不久的UI设计新手&#xff0c;学习UI设计课程都会让你做出更美观、更有影响力的UI界面设计作品。现在网上有很多网上的UI设计课程。通过这些课程&#xff0c;你可以自己学习、掌握一些UI设计的基础…

【Jmeter】生成html格式接口自动化测试报告

jmeter自带执行结果查看的插件&#xff0c;但是需要在jmeter工具中才能查看&#xff0c;如果要向领导提交测试结果&#xff0c;不够方便直观。 笔者刚做了这方面的尝试&#xff0c;总结出来分享给大家。 这里需要用到ant来执行测试用例并生成HTML格式测试报告。 一、ant下载安…

k8s之集群调度

目录 调度 工作机制 调度过程 调度算法 优先级 指定调度节点 调度 Kubernetes 是通过 List-Watch 的机制进行每个组件的协作&#xff0c;保持数据同步的&#xff0c;每个组件之间的设计实现了解耦。 用户是通过 kubectl 根据配置文件&#xff0c;向 APIServer 发送命令…

linux远程桌面管理工具xrdp

一、概述 我们知道&#xff0c;我们日常通过vnc来远程管理linux图形界面&#xff0c;今天分享一工具Xrdp&#xff0c;它是一个开源工具&#xff0c;允许用户通过Windows RDP访问Linux远程桌面。 除了Windows RDP之外&#xff0c;xrdp工具还接受来自其他RDP客户端的连接&#xf…

C# Winform串口助手

界面设置 修改控件name属性 了解SerialPort类 实现串口的初始化&#xff0c;开关 创建虚拟串口 namespace 串口助手 {public partial class Form1 : Form{public Form1(){InitializeComponent();}private void Form1_Load(object sender, EventArgs e){//在设计页面已经预先…

Map和Set(JAVA)

本篇文章建议在了解了哈希表和二叉搜索树后食用更佳。 链接: 二叉搜索树 和 哈希表 (JAVA) Map和Set都是一种专门用来进行搜索的容器或者数据结构&#xff0c;其搜索的效率与其具体的实例化子类有关。 Map接口 Map是一个接口&#xff0c;不能直接实例化对象&#xff0c;如果…

vue3源码地址

https://github.com/vuejs/core

API接口宝藏:免费好用资源分享

天气预警&#xff1a;获取指定城市当前生效中的各类天气预警&#xff0c;如寒潮蓝色预警信号&#xff0c;或一次性拉取全国所有生效中的天气预警。预警数据来自国家预警中心。 IP归属地-IPv4区县级&#xff1a;根据IP地址查询归属地信息&#xff0c;包含43亿全量IPv4&#xff…