前言:

我们都用过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迭代器和函数对象时,一般还是值传递比较高效。

最新文章

  1. D3D三层Texture纹理经像素着色器实现渲染YUV420P
  2. mysql count(*)和count(列)速率
  3. IntelliJ IDEA 当pom.xml更新时,自动加载pom.xml
  4. (五)stm32工程代码HardFault异常查错调试方法
  5. resharper 7.x 注册码key
  6. iOS已发布应用中对异常信息捕获和处理
  7. Docker&Kubernetes沙龙干货集锦:容器集群管理利器kubernetes详谈-CSDN.NET
  8. [转] C++虚函数与虚函数表
  9. centos6.5编译android-2.2_froyo的几个问题jdk,gcc,arm-gcc
  10. 二cha树
  11. 弹性布局 - flex对齐
  12. 树莓派中QT实现串口通讯
  13. rsync3.1.3的编译安装和常用操作
  14. BZOJ.4052.[Cerc2013]Magical GCD(思路)
  15. 微信小程序之路由
  16. Again Prime? No Time. UVA - 10780(质因子分解)
  17. Android中如何让DialogFragment全屏(DialogFragment fullscreen)
  18. linux 安装mysql yum方式
  19. Composer 的简介、安装及使用
  20. Python3.6学习笔记(六)

热门文章

  1. Imageview使用记录
  2. 我的WCF之旅(1):创建一个简单的WCF程序
  3. oracle 问题若干 提醒注意
  4. 17、手势(Gesture)
  5. Velocity - 单例还是非单例
  6. js基础第3天
  7. VBScript: Windows脚本宿主介绍
  8. windows 下Python import 导入自定义模块
  9. 从IRP说起(转)
  10. 在ASP.NET MVC中修改默认代码生成/支架模板