尽量用pass-by-reference-to-const(const引用)替换pass-by-value(传值)
默认情况下C++以pass-by-value传递对象至函数(或从函数返回)。
eg1:
class Person { public: Person(); virtual ~Person(); private: std::string name; std::string address; }; class Student: public Person { public: Student() ~Student(); private: std::string schoolName; std::string schoolAddress; };
考虑下面调用函数:
bool validateStudent(Student s); // 函数以 by value 方式接受参数 Student plato; bool platoIsOk = validateStudent(plato); // 调用函数
Student的copy构造函数会被调用,以plato为蓝本将s初始化。而当validtaeStudent返回时s会被销毁。详细深究的话,应该是以by value方式传递一个Student对象会导致调用一次Student copy构造函数,一次Person copy构造函数,4次String copy构造函数;相应销毁时总共需要调用6次析构函数。所以总成本是“六次构造函数和六次析构函数”!
使用pass by reference to const进行回避:
bool validateStudent(const Student& s);
这种传递方式效率就高很多,没有任何构造函数或析构函数被调用,因为没有对象被创建。这里的const使用是重要的,不这样做的话调用者会忧虑validateStudent会不会改变他们传入的哪个Student。
以by reference方式传递参数还可以避免slicing(对象切割)问题。
如果函数参数是基类对象,当传入一个派生类对象时,会造成派生类对象相比基类对象“之所以是个派生类对象”的所有特性化信息都会被切除。解决切割(slicing)问题的办法,就是以by reference to const的方式传递参数。
闲谈:有一次面试的时候问到了我这个问题,没有很好的回答上来“多态发生为什么需要传指针而不直接传递对象,传递对象有什么后果?”,现在可以很好的总结出答案。
由C++编译器的角度来看,references往往以指针实现出来,一次pass by reference 通常意味真正传递的是指针。如果对象属于内置类型(例如int),pass by value往往比pass by reference的效率高些(原因请看:C++ 传参时传内置类型时用传值(pass
by value)方式效率较高)。
1、内置类型都相当小,因此有人觉得,小型types都是pass-by-value的合格候选人,这个理论不可靠,对象小并不意味着其copy构造函数并不昂贵。许多对象(包括大多数STL容器)内容的东西只比一个指针多一些,但复制这种对象却需承担“复制那些指针所指的每一样东西”,那将非常昂贵。
2、即使小型对象拥有并不昂贵的copy构造函数,但效率优化上可能有争议。某些编译器会针对“内置类型”进行优化,比如某些编译器拒绝把只由一个double组成的对象放进缓存器,但是很乐意在一个正规基础上对光秃秃的doubles那么做。这种情况下,更应该以by reference方式传递此等对象。
3、作为一个用户自定义类型,其大小容易有所变化。一个type目前虽然小,将来也许会变大,因为其内部实现可能改变。
结论:
1、尽量以pass-by-reference-to-const替换pass-by-value,前者通常毕竟高校,并可避免切割问题(slicing problem)。
2、以上规则并不适用于内置规则,以及STL的迭代器和函数对象。对它们而言,pass-by-value往往比较适当。
尽量用pass-by-reference-to-const(const引用)替换pass-by-value(传值)的更多相关文章
- 读书笔记_Effective_C++_条款二:尽量以const, enum, inline替换#define
其实这个条款分成两部分介绍会比较好,第一部分是用const和enum替换不带参的宏,第二部分是用inline替换带参的宏. 第一部分:用const和enum替换不带参宏 宏定义#define发生在预编 ...
- void fun() const{}; const void fun(){}; 和void const fun(){}; 的区别?
void fun() const{}; const void fun(){}; 和void const fun(){}; 的区别? const void fun(){};和void const fun ...
- Book. Effective C++ item2-尽量使用const, enum, inline替换#define
##常规变量 c++里面的#define后面的定义部分,是不算代码的一部分的.所以如果你使用#define: #define ASPECT_RATIO 1.653 你希望这个代号ASPECT RATI ...
- int *const && int const * && const int *的区别
ANSIC允许声明常量,常量和变量不同,常量就是不可以改变的量,用关键字const来修饰 比如:const int a int const a 以上两种声明方式是一样的,我们不需要考虑const和in ...
- C++ Prime:const的引用
可以把引用绑定到const对象上,就像绑定到其他对象上一样,我们称之为对常量的引用.与普通引用不同的是,对常量的引用不能被用作修改它所绑定的对象: ; const int &r1 = ci; ...
- const 相关知识 const和指针、const和引用
以前老是对const概念不清不楚,今天算是好好做个笔记总结一下.以下内容包括1)常量指针(指针本身是常量),2)指针常量(指针指向的是常量对象),3)常量引用,4)const成员函数. 常量指针,指针 ...
- [转]为什么复制构造函数的参数需要加const和引用
[转]为什么复制构造函数的参数需要加const和引用 一.引言 1.0在解答这个问题之前,我们先跑个小程序,看下调用关系. #include <iostream> using namesp ...
- const的引用
const的引用 对常量的引用:把引用绑定到const对象上,就像绑定到其他对象上一样,不能被用作修改它所绑定的对象: ; const int &r1 = ci;//正确:引用及其对应的对象都 ...
- int *p,cons int *p,int const *p,int * const p,const int * const p,int const * const p的差别
加有constkeyword的几种情况的辨析 const修饰的代码 含义(特点) 等价性 int *p = # 1. 能够读自己 2. 能够通过*p改自己 ...
- 【C++编程基础】(1)—— 函数原型声明、函数模板、引用、const 常引用、const 常量指针
一.函数原型声明: 1.函数声明告诉编译器函数的名称,和如何调用函数(返回类型和参数):函数定义提供了函数的实际主体. 2.强制性的:在C++中,如果函数调用的位置在函数定义之前,则要求在函数调用之前 ...
随机推荐
- ViewPager实现滑屏切换页面及动画效果(仿优酷客户端)
找了许多实现该功能的例子,但效果都不很理想,于是自己结合网上的资源及自己的总结,整理了一下,发出来,供大家参考.这个是自己做的,仿优酷客户端的. 先看效果: ****************** ...
- Python 2.7的字典实现简化版(C语言)
这是一个能自动调整大小的哈希字典,外部接口实现了下列功能. 1.字典级别: 创建字典 dict_new 归零字典 dict_clear 2.键值级别: 查找 dict_search 强制查找 dict ...
- Android Multimedia框架总结(五)多媒体基础概念
转载请把头部出处链接和尾部二维码一起转载,本文出自: http://blog.csdn.net/hejjunlin/article/details/52431887 上篇中介绍了MediaPlayer ...
- Linux Java开发坏境搭建,Ubuntu-jdk+tomcat+eclipse+svn 包安装详细操作
更新时间2015-03-15 更新2015-04-12 svn安装更新 第一步 安装jdk (在linux上使用yum安装JDK http://blog.chinaunix.net/uid-1546 ...
- 全文检索概念,Lucene大致结构
1.1 常见的全文检索 1) 在window系统中,可以指定磁盘中的某一个位置来搜索你想要得到的东西. 2) 在myeclipse中,点击Help->Help Contents,可以利用搜索功能 ...
- JAVA面向对象-----构造方法
我们人出生的时候,有些人一出生之后再起名字的,但是有些人一旦出生就已经起好名字的.那么我们在java里面怎么在对象一旦创建就赋值呢? 构造方法作用 构造方法作用:对对象进行初始化. 构造函数与普通的函 ...
- Android简易实战教程--第二十一话《内容观察者监听数据库变化》
当数据库的数据发生改变,我们又想知道具体改变的情况时,就需要对数据库的变化情况做一个监控.这个任务,就由内容观察者来完成.下面这个案例,为短信数据库注册内容观察者,来监控短信的变化情况,当短信数据库发 ...
- Java中循环声明变量方法
Java循环声明变量 之前想这样做,但是网上一直搜索不到,下面是我的方式 项目中 // 得到需要查询外表的数量,然后分别创建缓存,插入数据多的时候如果编码在缓存里面,就不需要再去查询数据库了.key: ...
- Dynamics CRM 开启EmailRouter日志记录
找到mailrouter的安装路径,在service文件夹下找到"Microsoft.Crm.Tools.EmailAgent.xml"这个文件,已管理员方式打开,找到loglev ...
- androidpn-server笔记及BUG修改
上篇讲了androidpn的client端,这篇该讲一下我使用androidpn-server端的笔记了. 这里我使用的androidpn是tomcat版的,由不知哪位大神移植并修复了部分bug的版本 ...