【Effective C++】设计与声明——reference篇
以pass-by-reference-to-const替换pass-by-value
缺省情况下C++以by value方式传递对象至(或来自)函数。除非你另外指定,否则函数参数都是以实际实参的复件(副本)为初值,而调用端所获得的亦是函数返回的一个复件,这些复件(副本)由对象的copy构造函数产出,这可能使得pass-by-value成为昂贵的(费时的)操作。
好处1:高效,避免副本对象的创建
考虑以下的继承体系:
class Person{
public:
Person();
virtual ~Person();
private:
string name;
string address;
};
class Student:public Person{
public:
Student();
~Student();
private:
string schoolName;
string schoolAddress;
};
现在考虑以下代码,
bool validateStudent(Student s); //函数需要一个student实参(by value)并返回它是否有效
Student plato;
bool IsOK = validateStudent(plato); //调用函数
在调用函数时,Student的copy构造函数会被调用,以plato为蓝本将s初始化,在函数返回时,s又会被销毁。因此对此函数而言,参数的传递成本是“一次Student Copy构造函数调用,加上一次Student析构函数调用”。注意,Student对象内有两个string对象,所以每次构造一个Student对象也就构造了两个string对象。此外,Student对象继承自Person对象,所以每次构造Student对象也必须构造出一个Person对象,Person对象又有两个string对象在其中。。。因此以by-value方式传递一个Student对象,总体成本是“六次构造函数和六次析构函数”!
如果传递对象的引用,高效的多:
bool validateStudent(const Student& s);
没有新的对象被创建,const也会保证不对s做任何修改。
好处2:避免对象切割问题
当一个derived class对象以value方式传递并视为一个base class对象,base class的copy构造函数会被调用,derived class对象的特性会被全部切割掉:
class Person{
public:
...
string name() const;
};
class Student:public Person{
public:
...
string name() const;
};
调用:
void show(Person p){
cout<<p.name();
}
Student s;
show(s);
此时调用的是Person::name()。解决切割问题的方法是以引用传递参数:
void show(const Person& p)
注意:内置类型,STL的迭代器和函数对象,往往pass-by-value比较适当。
必须返回对象时,别妄想返回其reference
考虑有理数Rational,有个友元操作符*,返回Rational对象。
Rational operator*( const Rational &lhs, const Rational &rhs ) {
Rational result = ...
return result;
}
返回对象,导致临时对象的构造,析构。效率低,因此会想返回方法内局部对象的引用,这种方法不可行,为什么?
1. 定义一个局部变量,就是在stack空间创建对象,方法执行完毕,局部对象销毁。假如返回方法内局部对象的引用,方法执行完,局部对象销毁,这时候,引用指向一堆垃圾。
2.或者在heap上构造一个对象,返回引用。这也不可行,首先,要求客户端负责delete,这不合理。其次,退一步说,就算客户负责,执行delete。但是有些情况,客户无法执行delete。比如:Rational d = a*b*c; a*b的结果没有暴露出来,客户无法执行delete。
3. 既然方法内的局部对象会销毁,你可能会想返回一个reference指向方法内的local static对象,但是这会导致下面的诡异情况:无论何时,a*b == c*d 总是为真。为什么?
local static对象只初始化一次,a*b修改local static对象的值,并返回其引用,c*d也修改local static对象的值,并返回其引用。它们是同一个对象的别名,当然永远相等。只不过,后一次的修改覆盖了前一个修改。
因此,对于这种情况,就让方法返回对象。为了正确的行为,必须付出一定代价。需要说明的是,通过RVO技术,编译器可以进行优化,避免这种代价。
结论:绝不要返回pointer或reference指向一个local stack对象,返回reference指向一个heap-allocated对象,返回pointer或reference指向一个local static对象而可能同时需要多个这样的对象。
【Effective C++】设计与声明——reference篇的更多相关文章
- Effective C++ ——设计与声明
条款18:让接口更容易的被使用,不易误用 接口设计主要是给应用接口的人使用的,他们可能不是接口的设计者,这样作为接口的设计者就要对接口的定义更加易懂,让使用者不宜发生误用,例如对于一个时间类: cla ...
- Effective C++ —— 设计与声明(四)
条款18 : 让接口容易被正确使用,不易被误用 欲开发一个“容易被正确使用,不容易被误用”的接口,首先必须考虑客户可能做出什么样的错误操作. 1. 明智而审慎地导入新类型对预防“接口被误用”有神奇疗 ...
- 《Effective C++》第4章 设计与声明(1)-读书笔记
章节回顾: <Effective C++>第1章 让自己习惯C++-读书笔记 <Effective C++>第2章 构造/析构/赋值运算(1)-读书笔记 <Effecti ...
- 《Effective C++》第4章 设计与声明(2)-读书笔记
章节回顾: <Effective C++>第1章 让自己习惯C++-读书笔记 <Effective C++>第2章 构造/析构/赋值运算(1)-读书笔记 <Effecti ...
- 《Effective C++》阅读总结(四): 设计、声明与实现
第四章: 设计与声明 18. 让接口更容易被正确使用,不易被误用 将你的class的public接口设计的符合class所扮演的角色,必要时不仅对传参类型限制,还对传参的值域进一步限制. 19. 设计 ...
- EffectiveC++ 第4章 设计与声明
我根据自己的理解,对原文的精华部分进行了提炼,并在一些难以理解的地方加上了自己的"可能比较准确"的「翻译」. Chapter4 设计与声明 Designs and Declarat ...
- [Effective Java] 创建和销毁对象篇
[Effective Java] 创建和销毁对象篇 1. 优先考虑用静态工厂方法代替构造器 优点: - 静态工厂方法相比于构造器,它们有名称 - 不需要每次在使用的时候创建一个对象 - 可以返回原返回 ...
- 【学习记录】第一章 数据库设计-《SQL Server数据库设计和开发基础篇视频课程》
一.课程笔记 1.1 软件开发周期 (1)需求分析阶段 分析客户的业务和数据处理需求. (2)概要设计阶段 设计数据库的E-R模型图,确认需求信息的正确和完整. /* E-R图:实体-关系图(Ent ...
- Effective C++笔记:设计与声明
条款18:让接口容易被正确使用,不易被误用 1,好的接口很容易被正确使用,不容易被误用.你应该在你的所有接口中努力达成这些性质. 2,“促进正使用”的办法包括接口的一致性,以及与内置类型的行为兼容. ...
- Effective C++笔记04:设计与声明
条款18:让接口easy被正确使用,不易被误用 1,好的接口非常easy被正确使用,不easy被误用.你应该在你的全部接口中努力达成这些性质. 2,"促进正使用"的办法包含接口的一 ...
随机推荐
- Android Studio制作简单登录界面
实现目标 应用线性布局设计登录界面,要求点击输入学号时弹出数字键盘界面,点击输入密码时弹出字母键盘,出现的文字.数字.尺寸等全部在values文件夹下相应.xml文件中设置好,使用时直接引用.当用户名 ...
- 【进阶篇】Java 实际开发中积累的几个小技巧(二)
目录 前言 六.自定义注解 6.1定义注解 6.2切面实现 6.3业务使用 七.抽象类和接口 7.1隔离业务层与 ORM 层 7.2隔离子系统的业务实现 7.3选择对比 文章小结 前言 笔者目前从事一 ...
- CentOS7.9 systemctl
目录 命令格式 语法 加载配置文件 关机和开机 unit 文件存放位置 unit 格式说明 service unit file 文件构成部分 unit 段的常用选项 service 段的常用选项 in ...
- 性能透明提升 50%!SMC + ERDMA 云上超大规模高性能网络协议栈
简介: 新的协议栈是不是重新发明轮子?一个协议栈能否解决所有问题?适配所有场景? 编者按:当前内核网络协议栈有什么问题?新的协议栈是不是重新发明轮子?一个协议栈能否解决所有问题?适配所有场景?本文整理 ...
- 为了让你在“口袋奇兵”聊遍全球,Serverless 做了什么?
简介: 江娱互动是一家新兴的游戏企业,自 2018 年成立伊始,江娱互动就面向广阔的全球游戏市场,通过创造有趣的游戏体验,在竞争激烈的游戏市场占得一席之地.仅仅 2 年的时间,江娱互动就凭借 Topw ...
- ClickHouse Keeper 源码解析
简介:ClickHouse 社区在21.8版本中引入了 ClickHouse Keeper.ClickHouse Keeper 是完全兼容 Zookeeper 协议的分布式协调服务.本文对开源版本 C ...
- Hologres揭秘:高性能原生加速MaxCompute核心原理
简介: Hologres技术揭秘系列持续更新中,本期我们将带来Hologres高性能原生加速查询MaxCompute的技术原理解析. Hologres(中文名交互式分析)是阿里云自研的一站式实时数仓, ...
- 系统架构面临的三大挑战,看 Kubernetes 监控如何解决?
简介: 随着 Kubernetes 的不断实践落地,我们经常会遇到负载均衡.集群调度.水平扩展等问题.归根到底,这些问题背后都暴露出流量分布不均的问题.那么,我们该如何发现资源使用,解决流量分布不均 ...
- Paillier半同态加密:原理、高效实现方法和应用
简介: <数据安全法>已于9月1日起正式实施,两个月后<个人信息保护法>也将开始施行,意味着数据安全和隐私保护方面的监管将会在年内陆续到位.在合规收紧大背景下,"数 ...
- 一款基于Vue3实现的漂亮且功能强大的在线海报设计器
大家好,我是 Java陈序员. 我们在工作中经常需要设计各种各样的图片,海报.产品图.文章图片.视频/公众号等. 我们可以选择使用 PS 来设计图片,但是有时候想快速完成任务,有没有一款工具支持快速生 ...