前言:

我们都用过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. linux测试题

    http://www.2cto.com/os/201307/225399.html  2013最新linux运维面试题 在对linux基本知识的归纳总结之后,这里是一份linux的测试题.希望能帮助大 ...

  2. Java、JSP获得当前日期的年、月、日

    Java package com.ob; import java.text.ParseException; import java.text.SimpleDateFormat; import java ...

  3. jquery图片轮播-插件

    更新内容: 1. 页面结构和css样式必定类似下边放置 2. 点击左右按钮,实现左右滑动. 3. 这一般用于多个图片轮播使用,简化并优化代码. 若因不同需求,均可自行将插件scrollimgplus. ...

  4. DOM的定义及DOM相关

    DOM : Document Object Model 文档对象模型文档:html页面文档对象:页面中元素文档对象模型:定义 为了能够让程序(js)去操作页面中的元素 DOM会把文档看作是一棵树,同时 ...

  5. 静态Web开发 HTML

    静态Web开发 一章 HTML(Hyper Text Markup Language) 1节html入门 HTML超文本标记语言由浏览器解释执行开发人员编写的超文本文档就是网页 XHTMLHTML升级 ...

  6. put a ContextMenu into the header of a TabPage z

    publicclassMyTabControl:TabControl { protected override void OnMouseUp(MouseEventArgs e){ if(e.Butto ...

  7. 2015长春 HDU 5534 Partial Tree

    题意:有n个结点,n-1条边,现在要把这n个结点连成一棵树,给定了f(i),表示度为i的结点的价值是f(i).现在问如何连能够使得Σf(i)的值最大. 思路:每个点至少一个度,所以可分配的度数为n-2 ...

  8. PHP编码规范整理,很全很实用(图文版)

    有一个组织叫做“php互操作性框架制定小组”,这个小组的主要目的是制定各种PHP编码规范的,下面就是我根据小组提供的建议整理的一些常用的编码规范. PSR-1: 1.PHP代码文件必须以<?ph ...

  9. ffmpeg编码YUV420视频序列

    依旧是这里的测试序列 http://www.cnblogs.com/zzugyl/p/3678865.html测试了JM和libx264的编解码质量后来用ffmpeg转码 发现忘记了命令行转码的命令网 ...

  10. 字符串匹配算法——KMP算法学习

    KMP算法是用来解决字符串的匹配问题的,即在字符串S中寻找字符串P.形式定义:假设存在长度为n的字符数组S[0...n-1],长度为m的字符数组P[0...m-1],是否存在i,使得SiSi+1... ...