默认情况下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(传值)的更多相关文章

  1. 读书笔记_Effective_C++_条款二:尽量以const, enum, inline替换#define

    其实这个条款分成两部分介绍会比较好,第一部分是用const和enum替换不带参的宏,第二部分是用inline替换带参的宏. 第一部分:用const和enum替换不带参宏 宏定义#define发生在预编 ...

  2. void fun() const{}; const void fun(){}; 和void const fun(){}; 的区别?

    void fun() const{}; const void fun(){}; 和void const fun(){}; 的区别? const void fun(){};和void const fun ...

  3. Book. Effective C++ item2-尽量使用const, enum, inline替换#define

    ##常规变量 c++里面的#define后面的定义部分,是不算代码的一部分的.所以如果你使用#define: #define ASPECT_RATIO 1.653 你希望这个代号ASPECT RATI ...

  4. int *const && int const * && const int *的区别

    ANSIC允许声明常量,常量和变量不同,常量就是不可以改变的量,用关键字const来修饰 比如:const int a int const a 以上两种声明方式是一样的,我们不需要考虑const和in ...

  5. C++ Prime:const的引用

    可以把引用绑定到const对象上,就像绑定到其他对象上一样,我们称之为对常量的引用.与普通引用不同的是,对常量的引用不能被用作修改它所绑定的对象: ; const int &r1 = ci; ...

  6. const 相关知识 const和指针、const和引用

    以前老是对const概念不清不楚,今天算是好好做个笔记总结一下.以下内容包括1)常量指针(指针本身是常量),2)指针常量(指针指向的是常量对象),3)常量引用,4)const成员函数. 常量指针,指针 ...

  7. [转]为什么复制构造函数的参数需要加const和引用

    [转]为什么复制构造函数的参数需要加const和引用 一.引言 1.0在解答这个问题之前,我们先跑个小程序,看下调用关系. #include <iostream> using namesp ...

  8. const的引用

    const的引用 对常量的引用:把引用绑定到const对象上,就像绑定到其他对象上一样,不能被用作修改它所绑定的对象: ; const int &r1 = ci;//正确:引用及其对应的对象都 ...

  9. int *p,cons int *p,int const *p,int * const p,const int * const p,int const * const p的差别

     加有constkeyword的几种情况的辨析 const修饰的代码 含义(特点) 等价性 int *p = &num; 1.       能够读自己 2.       能够通过*p改自己 ...

  10. 【C++编程基础】(1)—— 函数原型声明、函数模板、引用、const 常引用、const 常量指针

    一.函数原型声明: 1.函数声明告诉编译器函数的名称,和如何调用函数(返回类型和参数):函数定义提供了函数的实际主体. 2.强制性的:在C++中,如果函数调用的位置在函数定义之前,则要求在函数调用之前 ...

随机推荐

  1. ROS机器人程序设计(原书第2版)补充资料 (拾) 第十章 使用MoveIt!

    ROS机器人程序设计(原书第2版)补充资料 (拾) 第十章 使用MoveIt! 书中,大部分出现hydro的地方,直接替换为indigo或jade或kinetic,即可在对应版本中使用. MoveIt ...

  2. Hazelcast源码剖析之Eviction

    v:* { } o:* { } w:* { } .shape { }p.MsoNormal,li.MsoNormal,div.MsoNormal { margin: 0cm; margin-botto ...

  3. 获取客户信息SQL

    /*取客户信息SQL*/ --客户信息 SELECT hou.name 业务实体, hca.account_number 客户编号, hp.party_name 客户名称, arp_addr_pkg. ...

  4. Hexo写博客

    hexo配置github Git Install hexo-deployer-git. $ npm install hexo-deployer-git –save 配置_config.yml文件 de ...

  5. HDFS:NameNode、DataNode、SecondaryNameNode

    可以一句话描述 HDFS:把客户端的大文件存放在很多节点的数据块中. HDFS设计原则: 1,文件以块(block)方式存储: 2,通过副本机制提高可靠度和读取吞吐量: 3,每个区块至少分到三台Dat ...

  6. 安卓2.x的版本使用4.x的主题

    现在,还有大部分安卓开发者在开发安卓APP时使用的是2.x的SDK版本,为了兼容2.x的手机这本倒无可厚非,但最令人头痛的就是2.x版本的主题是在太丑了,这是安卓刚推出时只考虑到了实用,并没考虑到美观 ...

  7. 密码学Hash函数

    定义: Hash函数H将可变长度的数据块M作为输入,产生固定长度的Hash值h = H(M). 称M是h的原像.因为H是多对一的映射,所以对于任意给定的Hash值h,对应有多个原像.如果满足x≠y且H ...

  8. Servlet处理流程分析-Servlet学习之旅(二)

    tomcat的处理处理客户端流程分析 tomcat即是servlet容器也具有web服务器的功能,即也具有html页面的功能. 1.首先客户端会将html请求发给tomcat内置的web服务器 2.w ...

  9. 收藏了4年的Android 源码分享

    Android 超过2个G的源代码集合~~几乎涵盖了所有功能效果的实现,一应俱全~~应有尽有~~ 360云盘地址:Android 各类源码集合汇总 (提取码:f930) 另外,附上Github上及自己 ...

  10. Java中封装性的使用

    //Java面对对象基本特性之一:封装性 //作用:保护某些属性和方法不被外部所看见 //封装的实现:通过关键字private声明 //鼠标右键--->Source---->Generat ...