前言:

我们都用过C的值传递方式,那么在C++情况下,值传递是怎样工作的呢?

比如:

int foo(int x);
int i;
foo(i);

1.程序内部先取得i的一个副本

2.将副本传递到foo函数

3.foo返回

这些副本的都是由拷贝构造函数产出的,当参数过多或者逻辑复杂时,就可能使得值传递成为费事的操作。

第一节:用pass-by-reference-to-const替换pass-by-value

我们先看类的值传递过程:

 class A {
public:
A() {cout << "Call A\n"; }
A(const A& aCopy) { // 拷贝构造函数
a = aCopy.a;
}
virtual ~A(){}
private:
string a;
}; class B: public A {
public:
B() {cout << "call B\n"; }
~B() {}
private:
string b;
}; void foo(B b) {
return;
}

接下来我们这么调用:

 B b1;                  // 会直接先调用A的构造函数
// 再调用B的构造函数
foo(b1); // 副本调用A的构造函数
// 再调用B的构造函数

上面并不是调用的所有数据,因为我们还有类的string成员!

在每次构造的时候都会调用string的构造函数,因此除了调用一次A的构造函数和一次B的构造函数,我们还额外调用了两次string的构造函数。

另外,我们还需要调用相对应的析构函数,因此上面的代码调用次数总和为:4次构造函数+4次析构函数。

简单的一个赋值,就导致这么多次函数调用,效率是问题!

方案:我们可以使用const引用来解决这个问题。在这种方式下,任何构造函数和析构函数都不需要调用。

void foo(const B& b) {
return;
}

因为引用是直接对对象进行操作的,不存在副本之说。另外定义为const,是为了不让传递的实参被误改!

除了调用函数次数减少,使用const引用还可以带来以下的好处。

★避免对象切割问题(slicing)

用一个形象的例子来解释:

 class A {
public:
A() {cout << "Call A\n"; }
A(const A& aCopy) {
a = aCopy.a;
}
virtual ~A(){}
private:
string a;
}; class B: public A {
public:
B() {cout << "call B\n"; }
~B() {}
private:
string b;
}; void foo1(A a) {
return;
}

如果我们这个时候将子类对象传入foo1()函数。

B b1;
foo1(b1); // 子转父

在这个时候,b1在值传递的时候会被认为是一个基类对象,从而产生一个基类副本,A的拷贝构造函数被会调用,于是子类B中的特性会被全部切割,仅仅留下一个基类对象!

而解决切割问题的最好方法:就是使用const引用传值!

void foo1(const A& a) {  // 不再调用A的拷贝构造函数!
return;
}

第二节:基本类型的传递    

如果我们去探寻C++编译器的底层,就会发现:引用往往以指针实现出来,因此通过指针传递通常意味着真正传递的是指针。

因此,对于内置类型而言,值传递的效率其实比引用传递的效率高些。

对于STL的迭代器和函数对象而言,这个结果也是适用的。

◆总结

1.尽量以pass-by-reference-to-const替换pass-by-value。前者通常比较高效,并可避免切割问题(slicing problem);

2.在针对内置类型以及STL迭代器和函数对象时,一般还是值传递比较高效。

[Effective C++ --020]宁以pass-by-reference-to-const替换pass-by-value的更多相关文章

  1. [GeekBand ] 利用 pass by reference -to -const 编写高效规范的 c++代码

    本文参考资料 :  GeekBand 侯捷老师,学习笔记 Effective C ++ 侯捷译 条款20 开发环境采用:VS2013版本 首先:分析值传递的缺点 (一) class Person{ p ...

  2. 值传递:pass by value(按值传递) 和 pass by reference(引用传递)-[all]-[编程原理]

    所有的编程语言,都会讨论值传递问题. 通过一个js示例直观认识 //理解按值传递(pass by value)和按引用传递(pass by reference) //pass by value var ...

  3. 《Effective C++》读书笔记 条款02 尽量以const,enum,inline替换#define

    Effective C++在此条款中总结出两个结论 1.对于单纯常量,最好以const对象或enum替换#define 2.对于形似函数的宏,最好改用inline函数替换#define 接下来我们进行 ...

  4. Does Java pass by reference or pass by value?(Java是值传递还是引用传递) - 总结

    这个话题一直是Java程序员的一个热议话题,争论不断,但是不论是你百度搜也好还是去看官方的文档中所标明的也好,得到的都只有一个结论:Java只有值传递. 在这里就不贴代码细致解释了,让我们来看看一些论 ...

  5. Effective C++_笔记_条款03_尽可能使用const

    (整理自Effctive C++,转载请注明.整理者:华科小涛@http://www.cnblogs.com/hust-ghtao/) 关键字const多才多艺,语法变化多端.关于const的基本用法 ...

  6. 对常量的引用(reference to const)的一般用途(转载)

    如果是对一个常量进行引用,则编译器首先建立一个临时变量,然后将该常量的值置入临时变量中,对该引用的操作就是对该临时变量的操作.对C++常量引用可以用其它任何引用来初始化:但不能改变. 关于引用的初始化 ...

  7. Effective C++ -----条款23:宁以non-member、non-friend替换member函数

    宁可拿non-member non-friend函数替换member函数.这样做可以增加封装性.包裹弹性(packaging flexibility)和机能扩充性.

  8. Effective C++学习笔记 条款02:尽量以const,enum,inline替换 #define

    尽量使用const替换 #define定义常量的原因: #define 不被视为语言的一部分 宏定义的常量,预处理器只是盲目的将宏名称替换为其的常量值,导致目标码中出现多分对应的常量,而const定义 ...

  9. Effective C++_笔记_条款02_尽量以const、enum、inline替换#define

    (整理自Effctive C++,转载请注明.整理者:华科小涛@http://www.cnblogs.com/hust-ghtao/) 这个条款或许改为“宁可以编译器替换预处理器”比较好,因为或许#d ...

随机推荐

  1. [Mac][phpMyAdmin] [2002] No such file or directory

    我从phpMyAdmin的官网下载了最新版,将它解压到 /Library/WebServer/Documents 下,然后把文件夹改名 phpmyadmin . 接着输入在浏览器中输入 localho ...

  2. Windows 下目录及文件向Linux同步

    本文解决的是Windows 下目录及文件向Linux同步的问题,Windows向 Windows同步的请参考:http://www.idcfree.com/article-852-1.html 环境介 ...

  3. 剑指Offer:打印从1到最大的n位数

    题目:输入数值n,按顺序打印从1到最大的n位数,例如输入n=3,则从1,2,3,一直打印到999 陷阱:若使用循环遍历 1- 999...9 并依次输出,当位数n过大时,无论将其存入int或long或 ...

  4. Sping表达式语言--SpEL

    Spring表达式语言---SpEL 是一个支持运行时查询和操作对象的强大的表达式语言 语法类似于EL:SpEL使用#{...}作为定界符,所有在大括号中的字符都将被认为是SpEL SpEL为bean ...

  5. 在PowerDesigner中设计物理模型2——约束

    唯一约束 唯一约束与创建唯一索引基本上是一回事,因为在创建唯一约束的时候,系统会创建对应的一个唯一索引,通过唯一索引来实现约束.不过唯一约束更直观的表达了对应列的唯一性,使得对应索引的目的更加清晰,所 ...

  6. tdx api z

    调用TdxAPI.dll函数 .DLL命令 TdxInit, 逻辑型, "TdxApi.dll", "TdxInit", , 初始化通达信实例,成功时返回tru ...

  7. CCR

    不用任何与创建线程.资源互斥有关系的API写多线程程序 这次的例子,是一个很简单的控制台,她将面对瞬间提交的百万的数据,而面不改色(CPU.内存非常平稳),队列中始终只保存最新的数据,每次只处理cpu ...

  8. HDU 3001 Travelling 3进制状压dp

    题意:10个点,若干条边,边有花费,每个点最多走两次,求走过所有点,花费最少 分析:因为每个点最多走两次,所以联想到3进制,然后枚举状态,就行了(我也是照着网上大神的代码写的) #include &l ...

  9. 【译】 AWK教程指南 2概述

    2.1 为什么用AWK 由于awk具有上述特色,在问题处理的过程中,可轻易使用awk来撰写一些小工具:这些小工具并非用来解决整个大问题,它们只扮演解决个别问题过程的某些角色,可通过Shell所提供的p ...

  10. MFC定时器

    比较简单,在程序中可以找到原型. 在程序中我们经常要使用定时刷新的功能,典型的应用是在信息管理系统中表单要跟着数据库中的数据变动.MFC提供了定时器来完成这个功能. ================= ...