effective c++ 20 传引用代替传值

news/2024/11/8 15:03:10/

effective c++ 20 传引用代替传值

本节,作者开始讨论引用。我们知道c语言已经有了指针,通过指针我们也就可以修改变量本身,而不是修改变量的副本(传值), 那么在c++中又搞出来个引用, 那么其是不是有点重复?

分析

我们知道在函数的传参中,如果传递的是指针, 那么就不可避免的要进行取地址和解引用,如下面的这段代码所示,就需要使用"&“和”*"。这就可给我们的代码增加了一定的复杂性。其实c++引入引用也就是为了简化这种写法。

#include <iostream>void print(int* a)
{*a = 4;std::cout << *a << std::endl;
}int main()
{int a = 3;print(&a);
}

上面的代码修改成用引用的方式,是不是就简化了很多。

#include <iostream>void print(int& a)
{a = 4;std::cout << a << std::endl;
}int main()
{int a = 3;print(a);
}

因此我们在c++中,涉及传参的时候,要尽量使用引用。但是要强调的是,引用并不能取代指针,涉及内存的操作的时候,指针还是不可替代的。

由于引用有指针的特性,在传参的时候是没有copy的行为的。例如下面这个validateStudent函数,使用了常引用作为入参,避免了对象的拷贝。如果用传值的方式, 其内部有多个string对象要涉及拷贝,这将是低效的。

class Person
{
public:Person() : name("AAAA"), addr("BBBB"){}virtual ~Person() {}private:std::string name;std::string addr;
};class Student : public Person
{
public:Student() : schoolName("CCCC"), schoolAddr("DDDD"){}~Student() {}private:std::string schoolName;std::string schoolAddr;
};bool validateStudent(const Student& s);

另外, 由于引用的背后是由指针实现的,所以其将拥有"多态"的功能。 如下面中的printNameAndDisplay函数, 其入参是一个Window类的引用,在类的继承关系上,WindowWithScrollBars继承于Window。因此当传入的对象是Window对象时,w.display将调用window类的display方法,当传入的参数是WindowWithScrollBars类的对象时,w.display将调用WindowWithScrollBars类的display方法。

class Window
{
public:std::string name() const { return "WINDOW"; }virtual void display() const{std::cout << "Display: window" << std::endl;}
};class WindowWithScrollBars : public Window
{
public:void display() const{std::cout << "Display: window with scroll bars" << std::endl;}
};void printNameAndDisplay(const Window& w)
{std::cout << w.name();w.display();
}

上面主要讲解了传引用的好处, 那么什么时候我们引用考虑传值呢?

作者这里也给出了解答, 下面三种场景可以考虑直接传值:

  • 内置类型(只读不修改时)
  • STL迭代器
  • 函数对象

关于STL迭代器和函数对象为什么可以考虑传值,我在知乎上搜到了下面的解释,我觉得比较有道理:

很多时候迭代器可以做成可平凡复制的小对象(有时就是裸指针或裸指针直接外包),这时值传递迭代器和传递一个指针开销相同。不过例外也是存在的。

函数对象的话,无状态函数对象和函数指针是常见的情况。不过“大块头”的函数对象(如 std::function 或状态庞大的函数对象)也不能说少见。这时选择传值还是 const 引用可能就需要斟酌。

总结

  • 尽量以传常引用去替代传值。前者通常比较高效,并且可以避免切割问题。
  • 以上规则并不适用于内置类型 ,以及STL的迭代器和函数对象,对它们而言,传值往往比较合适。

http://www.ppmy.cn/news/83236.html

相关文章

七、SpringBoot从入门到精通

一、SpringBoot概述 Spring Boot是一个基于Spring框架的开发框架&#xff0c;用于快速构建能够立即运行的生产级Spring应用程序。它是Spring的一个子项目&#xff0c;致力于使Spring开发更加简单、快速和便捷。 二、SpringBoot基础程序 1、点击Spring Initializer&#xff0…

博客系统的后端设计(八) - 实现发布博客功能

文章目录 发布博客1. 约定前后端交互接口2. 服务器代码3. 客户端代码4. 出现的问题 发布博客 在原来的编辑页面点击发布文章按钮&#xff0c;是不会有什么效果的。 这是因为此时还不能实现前后端的交互。 1. 约定前后端交互接口 请求使用 POST&#xff0c;路径是 /blog title这…

大数据治理入门系列:数据血缘关系

血缘关系在人类社会中扮演着重要角色。大多数家庭是基于血缘关系形成的&#xff0c;而家庭作为社会的基本单元&#xff0c;对维系社会稳定发挥着重要关系。其实&#xff0c;数据之间也存在类似的血缘关系。数据从产生、加工、流转&#xff0c;一直到消亡&#xff0c;每个环节必…

【SpringMVC】| SpringMVC拦截器

目录 一&#xff1a;SpringMVC拦截器 1. 拦截器介绍 2. HandlerInterceptor接口分析 3. 自定义拦截器实现权限验证 一&#xff1a;SpringMVC拦截器 SpringMVC 中的 Interceptor 拦截器&#xff0c;它的主要作用是拦截指定的用户请求&#xff0c;并进行相应的预处理与后处理…

Spring Security 如何实现身份认证和授权?

Spring Security 是一个开源的安全框架&#xff0c;提供了基于权限的访问控制、身份认证、安全性事件发布等功能。在 Spring Boot 应用中使用 Spring Security 可以非常方便地实现用户身份认证和授权。 Spring Security 实现身份认证的主要方式是使用认证过滤器链&#xff0c;…

MySQL数据库中,在读已提交和可重复读这两个不同事务隔离级别下幻读的区别

目 录 1. 前 言1.1 并发事务存在的问题1.2 事务的隔离级别1.3 快照读和当前读 2. 不同事务隔离级别下幻读的区别2.1 读已提交下的幻读2.2 可重复读下的幻读2.2.1 情况一&#xff0c;无幻读2.2.2 情况二&#xff0c;有幻读2.2.3 情况三&#xff0c;有幻读 3. 小 结 1. 前 言 在…

基于 Prometheus 的 SLO告警实战

Prometheus是一个流行的开源监控系统&#xff0c;它可以帮助我们收集、存储和查询应用程序或系统的时间序列数据。在使用Prometheus进行监控时&#xff0c;通常需要根据服务水平指标&#xff08;Service Level Objectives&#xff0c;简称SLO&#xff09;来设置告警规则。 SLO…

linux学习[11]磁盘与文件系统(2):lsblkblkidpartedfdiskgdiskmkfs

文章目录 前言&#xff1a;1. 磁盘容量1.1 lsblk1.2 blkid1.3 parted 2. 磁盘分区2.1 fdisk/gdisk2.2 磁盘分区实例参考&#xff1a; 3. 磁盘格式化3.1 mkfs.xfs3.2 mkfs.ext43.3 mkfs.vfat 总结&#xff1a; 前言&#xff1a; 写了VMware的磁盘扩容之后&#xff0c;磁盘分区格…