您的位置:首页 > 产品设计 > UI/UE

函数参数之 传常引用(passed by reference to const)替换 传值(passed by value)

2015-07-12 11:19 393 查看
我们知道,对于一个c++程序员来说,相对于java 等其它面向对象语言而言,效率就是c++程序的生命所在,如何使得c++在拥有良好的面向对象特性(抽象,封装,继承,多态)特性上,极大的提高c++程序的效率呢?其中最关键的技巧就是在函数参数的传递过程中 以传常引用替换传值(Prefer pass-by-reference-to-const to pass-by-value), 传常引用替换传值为什么能够极大的提高c++程序的效率呢?下面请容小生 一一道来,如有争议 ,欢迎指出。

首先,我们得明白c++程序中 函数参数的传递方式

1.传值(pass-by-value)

2.传指针(pass-by-pointer)

3.传引用(pass-by-reference)

有些童靴可能会问到,你不是说,传常引用吗,这里为什么是没有常量性关键字 const,不要急,下面,小生会慢慢道来,但是既然提到了const 我们就必须明白,一旦你使用了关键字const ,你就告诉了编译器和团队中其他程序猿小伙伴们,这个对象不能再修改了的,它是不变的。关于关键字const 的详细讲解请参考小生的前面的博客

详解const

1.函数参数,函数返回值,传递过程中的传值(pass-by-vuale)

(1)效率

c++函数在形参与实参传递过程中,默认状态是以传值(by value)的形式进行传递对象。而各位猿都知道,以传值方式传递参数实际上传递的是以实参的副本为初值,而函数调用端获取的返回值也只是函数return返回值的一个副本。对于c程序来说,这种方式并没有什么不好,但是,各位猿都知道,继承,封装,多态,是c++对象的基本特性,那么问题就来了,这些副本都以对象的拷贝构造函数(copy constructors)产生,这就可能使得以传值的方式来进行参数传递会消耗太多的时间,代价比较昂贵,使得c++程序执行效率比较低,而相对于其它面向对象语言如Java ,效率是c++的生命所在,所以,从程序的执行效率来说,对于用户自定义类型(也就是类),以传值的方式来进行参数传递不可取。

(2)对象切割问题(slicing)

首先我们得明白什么是对象切割,对象切割是指在c++继承体系中,当一个派生类对象(derived class)以传值的方式进行传递,并且编译器把派生类对象视为一个(base class)基类对象时,此时c++编译器调用的只是基类的拷贝构造函数,而派生类所特有的特化性质全部被切割掉了,仅仅留下基类对象。也就是说 派生类对象自己所特有的部分全部没有复制,仅仅复制了基类对象所共有的属性。而以传值的方式来进行参数传递,对象切割问题无法解决。

在c++程序中,以传值方式进行参数传递,既然存在了(1)程序执行效率低(2)对象切割问题 两个致命问题,各位猿肯定会思考如何去解决,那么具体怎么去解决这个问题呢?各位猿不要心急,请容小生在后面慢慢道来.

2.函数参数传递 和 函数返回值以传常引用的方式(pass by reference to const )的方式进行传递

首先我们得明白什么是引用(reference),对于绝对部分c程序猿来说,c程序中最让我们头疼的莫过于对于指针的操作,所以c++标准委员会为了使c++更容易理解 ,所以引入了引用,但是到最后却又发现对于c++来说 ,指针又是必不可少的。关于指针和引用的联系和区别可以参考小生的博文详解c++引用与指针的联系与区别

简单来说,对对象的引用就是对原始对象的操作,任何作用于引用对象的操作都等同于对原始对象的操作,所以在函数参数的传递过程中 以传常引用的方式(pass by reference to const),形参和实参都是同一对象,不存在复制,也就不会调用拷贝构造函数,从而能够有效避免以传值方式带来的因为拷贝构造带来的低效率和对象切割问题。所以为了提高c++程序的执行效率和防止对象切割问题,对于用户自定义类型(也就是你自己写的类 )来说,在函数参数传递过程中尽量以传常引用代替传值。

3.传指针(pass by pointers)

对于指针我想绝大部分程序猿来说又爱又恨吧,爱是因为它带来极高的效率,恨的话,我想也没必要多说了,总之,一句话,你懂得!好了 言归正传,就像上文所说的,为了有效克服c语言中,指针的缺点,c++引入了引用这一概念,如果你对c++编译器底层理解的足够深的话,你会发现 ,c++的引用(reference)是以指针来实现的。因此传引用(pass by reference )通常意味着函数真正传递的是对象的指针。所以,如果函数参数类型是内置类型(如 int, char等等)而非用户自定义类型的话,函数参数以传值(pass by value)往往比传引用 (pass by reference)效率更高,当然了,对于像int 这样的内置类型也没有继承这一说法,就更不会发生对象切割了。同理,对于STL中的迭代器和函数对象而言,它们习惯上都被设计为传值,所以所以对于内置类型和STL的迭代器 ,函数对象而言,我们选择传值 的方式而不是传引用的方式来进行参数传递。因为内置类型都非常小,因此,肯能某些猿会这么认为,是不是所有小型的类型(type)不管是内置类型还是用户自定义类型只要它足够小,就可以选择以传值的方式来进行参数传递呢?这显然是不合理的。首先,类型对象小并不意味着其拷贝构造函数代价不高。例如 包括STL容器在内的许多对象成员变量只比指针多一些,但是复制这种对象却必须复制指针所指的每一样东西,代价非常高昂。其次,即使小型对象的拷贝构造函数 拷贝代价并不高,但在效率上还是有很多争议。因为不同的c++编译器对内置类型和用户自定义类型的处理方法截然不同,即使它们拥有相同的底层实现(也就是说内置类型和用户自定义类型拥有相同的 代码实现)。例如 有些c++编译器会把内置类型int等放入缓冲区,而不会把由int组成的一个用户自定义类型INT
class INT{int a;};
放进缓冲区。很显然,对于这样的C++编译器,内置类型执行速度更快。更何况,对于用户自定义类型来说,它的大小并不是固定不变的,可能在当前需求中,用户自定义类型很小,但是随着需求的改变,类型内部实现可能改变,我们甚至发现,即使c++编译器的改变都可能改变用户自定义类型的大小。所以我们可以合理假设传值“pass by value”的唯一对象就是内置类型,STL迭代器,和函数对象。对于用户自定义类型来说,不管其大小,尽量以传常引用(pass by referenc to const)替换传值。

2.学海拾贝

(1)对于内置类型,STL迭代器,函数对象,不管类型大小,都应该以传值的方式进行参数传递

(2)对于用户自定义类型(也就是你自己定义的类)来说,为了提高c++程序的执行效率和避免对象切割问题,我们应该以传常引用(pass by referenc to const )方式来进行参数传递。

3.感谢

心存感恩,才能走得更远。

感谢:Effective C++ Third Edition
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: