【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,"促进正使用"的办法包含接口的一 ...
随机推荐
- C语言专业课复试整理
C复试专业基础测试整理 运行C程序的步骤和方法 编辑.编译.连接和运行 . 编辑是用户把编写好的C语言源程序输入计算机,以文本文件的形式存放在磁盘上.其标识为:"文件名.c". 编 ...
- JavaScript中如何实现函数缓存?有哪些应用场景?
一.是什么 函数缓存,就是将函数运算过的结果进行缓存 本质上就是用空间(缓存存储)换时间(计算过程) 常用于缓存数据计算结果和缓存对象 const add = (a,b) => a+b;cons ...
- .netcore 使用Quartz定时任务
这是一个使用 .NET Core 和 Quartz.NET 实现定时任务的完整示例.首先确保已经安装了 .NET Core SDK.接下来按照以下步骤创建一个新的控制台应用程序并设置定时任务: 创建一 ...
- 对key值理解
key相当于一种身份标识标识,就像我们的身份证用来辨识一个人一样. 每个key对应一个组件, 相同的key react会认为是同一个组件,这样后续相同的key对应组件都不会被创建.... 而有了key ...
- 5款开源、美观、强大的WPF UI组件库
前言 经常看到有小伙伴在DotNetGuide技术社区交流群里提问:WPF有什么好用或者好看的UI组件库?,今天大姚给大家分享5款开源.美观.强大.简单易用的WPF UI组件库. WPF介绍 WPF ...
- 阿里云 VPC 内网性能测试最佳实践
简介:本文介绍了在阿里云 VPC 内网执行性能测试的方法.相较于传统的公网性能测试,VPC 内网性能测试完全在客户 VPC 环境进行,无需暴露服务到公网,安全性更高,灵活性更强. 作者:风起 背景 ...
- Java异步非阻塞编程的几种方式
简介: Java异步非阻塞编程的几种方式 一. 从一个同步的Http调用说起 一个很简单的业务逻辑,其他后端服务提供了一个接口,我们需要通过接口调用,获取到响应的数据. 逆地理接口:通过经纬度获取这个 ...
- SaaS服务的私有化部署,这样做最高效|云效工程师指北
简介:为了能够有效且高效地同时管理SaaS版本和私有化版本的发布过程,云效团队也结合云原生的基础设施和标准化工具(比如helm)进行了一系列的探索和实践,并将其中一些通能的能力进行了产品化.本文从问 ...
- 创新推出 | Serverless 场景排查问题利器:函数实例命令行操作
简介: 实例命令行功能的推出希望能消除用户使用 Serverless 的"最后一公里",直接将真实的函数运行环境展现给用户,此后 Serverless 将不再是一个"黑 ...
- 基于 Scheduled SQL 对 VPC FlowLog 实现细粒度时间窗口分析
简介: 针对VPC FlowLog的五元组和捕获窗口信息,在分析时使用不同时间窗口精度,可能得到不一样的流量特征,本文介绍一种方法将原始采集日志的时间窗口做拆分,之后重新聚合为新的日志做分析,达到更细 ...