关于传值与传引用的讨论

效率问题

对于用户自定义的类型来说,传引用一般要比传值高效。传引用不需要经过对象构造的过程,在《Effective C++》中作者举了个例子:

class Base

{

    pubilc:

                 Base();

                ~Base();

    private:

            std::string b1;

            std::string b2;

}



class Derive : public Base

{

    public:

                Derive();

                ~Derive();

    private:

            std :: string d1;

            std ::string d2;

}

此刻我们拥有一个派生类对象derive 。对derive传值的结果是共需要进行六次的构造函数的调用:对象本身的构造函数,对象内部数据成员string的构造,对象基类部分的构造函数,对象基类数据成员string的构造。同样的,待对象生命结束后,还要经历6次析构函数的调用。而传引用则不用进过如此多的构造与析构,甚至一次都不用。

对内置类型来说,传值的效率往往要高于传引用。内置类型包括了int,float ,double,指针类型等等。看下面的程序:

void f(int i)

{

    i = i + 1;

}

void g(int & i)

{

    i = i + 1;

}

int main()

{

    int i=10;

    f(i);

    g(i);

}

当通过传值调用函数f()时,其汇编代码为:

当通过传引用调用函数g()时,其汇编代码为:

可以看到,传引用比传值多了一次寻址操作,这是因为引用的实现往往基于指针,因此传引用通常意味着真正传递的是指针。

总结:

  1. **对内置类型来说,通常传值更高效。**
  2. **对用于自定义类型来所,传值要经历构造与析构过程,一般比较耗时。**

对象的切割问题

传值有时会引起对象的切割问题。就上面所示的两个类,当我们定义如下函数并进行传值调用时:

void func(Base B)

{

    ...

}

int main()

{

    Derive A;

    func(A);

}

编译器将调用Base类的复制构造函数来初始化B,初始化数据来源于A,但构造结果是个Base类对象:也就意味着A的特有部分的数据被切割掉了。在函数func中,B的行为是一个Base的行为而不是Derive的行为。

通过传引用,能够避免切割的问题:

void func(Base & B)

{

    ...

}

int main()

{

    Derive A;

    func(A);

}

此时在函数func内,对象B实际类型为Derive,通俗地将,B就是A。若希望在func中使用到实参的特性,传引用能够保证这一点。

STL中的使用情况

如果你打开STL中的源码,你会发现容器的iterator都是通过传值形式传参。在《Effective C++》中指出,对于内置类型、STL 迭代器和 STL 仿函数,pass-by-value 也是可以的,一般没有性能损失。在 x86-64 上,对于只有一个 指针成员且没有自定义复制构造函数的类,传值是可以通过寄存器进行的,就像传递普通 int 和指针那样。如上所示,传值是可以比传引用快的没有,因为它少了一次解引用的操作。

(完)

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏容器云生态

awk-grep-sed简单使用总结(正则表达式的应用)

正则表达式: 匹配一组字符: #[ns]a.\.xls  //[]用于限定字符;“.”用于匹配任意字符; \.用于转义"." 匹配到s/na*.xls  [n...

2599
来自专栏数据结构与算法

1081 线段树练习 2 单点查询及区间修改

1081 线段树练习 2 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 大师 Master 题目描述 Description ...

3189
来自专栏鸿的学习笔记

一句话讲明白基本排序

422
来自专栏Python爬虫与数据挖掘

Python正则表达式初识(五)

正则表达式的内容很丰富,今天小编继续给大家分享Python正则表达式的基础知识。今天要给大家的讲的特殊字符是竖线“|”。竖线“|”实质上是一个或的关系。

742
来自专栏JAVA技术站

shell学习二数组 原

类似与C语言,数组元素的下标由0开始编号。获取数组中的元素要利用下标,下标可以是整数或算术表达式,其值应大于或等于0。

481
来自专栏小樱的经验随笔

strncmp函数——比较特定长度的字符串

strncmp函数用于比较特定长度的字符串。 头文件:string.h。 语法  int strncmp(const char *string1, const ...

3279
来自专栏五分钟学算法

看完这个你还不会 插入排序 么

由于LeetCode上的算法题很多涉及到一些基础的数据结构,为了更好的理解后续更新的一些复杂题目的动画,推出一个新系列 -----《图解数据结构》,主要使用动画...

1043
来自专栏炉边夜话

java 异常处理学习笔记

<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

952
来自专栏cs

xml基本知识点

xml, Extensible Markup Language,可扩展的标记语言。 ? xml文档结构.jpg xml文档的规则 1.0 xml文档必须以一个...

3375
来自专栏决胜机器学习

《Redis设计与实现》读书笔记(六) ——Redis中的压缩列表

《Redis设计与实现》读书笔记(六) ——Redis中的压缩列表 (原创内容,转载请注明来源,谢谢) 一、概述 压缩列表(ziplist)是列表键(list)...

3897

扫码关注云+社区

领取腾讯云代金券