函数调用传值、传地址与引用的选择

来源:互联网 发布:jsp网上购物系统源码 编辑:程序博客网 时间:2024/06/05 16:12

从函数调用的角度理解三者之间的区别

  传值:   
  函数参数压栈的是参数的副本。   
  任何的修改是在副本上作用,没有作用在原来的变量上。  


  传指针:   
  压栈的是指针变量的副本。   
  当你对指针解指针操作时,其值是指向原来的那个变量,所以对原来变量操作。  


  传引用:   
  压栈的是引用的副本。由于引用是指向某个变量的,对引用的操作其实就是对他指向的变量的操作。

函数调用传值、传地址与引用的选择

1. 从功能上。按值传递在传递的时候,实参被复制了一份,然后在函数体内使用,函数体内修改参数变量时修改的是实参的一份拷贝,而实参本身是没有改变的,所以如果想在调用的函数中修改实参的值,使用值传递是不能达到目的的,这时只能使用引用或指针传递。例如,要实现两个数值交换。

void swap(int a int b)

void main(){

int a=1 b=2

swap(a b)

}

这样,在main()函数中的a b值实际上并没有交换,如果想要交换只能使用指针传递或引用传递,如:

void swap(int *pa int *pb)

void swap(int& ra int& rb)

2.从传递效率上。这里所说传递效率,是说调用被调函数的代码将实参传递到被调函数体内的过程,正如上面代码中,这个过程就是函数main()中的a b传递到函数swap()中的过程。这个效率不能一概而论。对于内建的int char short long float等4字节或以下的数据类型而言,实际上传递时也只需要传递1-4个字节,而使用指针传递时在32位cpu中传递的是32位的指针,4个字节,都是一条指令,这种情况下值传递和指针传递的效率是一样的,而传递double long long等8字节的数据时,在32位cpu中,其传值效率比传递指针要慢,因为8个字节需要2次取完。而在64位的cpu上,传值和传址的效率是一样的。再说引用传递,这个要看编译器具体实现,引用传递最显然的实现方式是使用指针,这种情况下与指针的效率是一样的,而有些情况下编译器是可以优化的,采用直接寻址的方式,这种情况下,效率比传值调用和传址调用都要快,与上面说的采用全局变量方式传递的效率相当。

再说自定义的数据类型,class struct定义的数据类型。这些数据类型在进行传值调用时生成临时对象会执行构造函数,而且当临时对象销毁时会执行析构函数,如果构造函数和析构函数执行的任务比较多,或者传递的对象尺寸比较大,那么传值调用的消耗就比较大。这种情况下,采用传址调用和采用传引用调用的效率大多数下相当,正如上面所说,某些情况下引用传递可能被优化,总体效率稍高于传址调用。

3. 从执行效率上讲。这里所说的执行效率,是指在被调用的函数体内执行时的效率。因为传值调用时,当值被传到函数体内,临时对象生成以后,所有的执行任务都是通过直接寻址的方式执行的,而指针和大多数情况下的引用则是以间接寻址的方式执行的,所以实际的执行效率会比传值调用要低。如果函数体内对参数传过来的变量进行操作比较频繁,执行总次数又多的情况下,传址调用和大多数情况下的引用参数传递会造成比较明显的执行效率损失。

综合2、3两种情况,具体的执行效率要结合实际情况,通过比较传递过程的资源消耗和执行函数体消耗之和来选择哪种情况比较合适。而就引用传递和指针传递的效率上比,引用传递的效率始终不低于指针传递,所以从这种意义上讲,在c++中进行参数传递时优先使用引用传递而不是指针。

4. 从类型安全上讲。值传递与引用传递在参数传递过程中都执行强类型检查,而指针传递的类型检查较弱,特别地,如果参数被声明为 void ,那么它基本上没有类型检查,只要是指针,编译器就认为是合法的,所以这给bug的产生制造了机会,使程序的健壮性稍差,如果没有必要,就使用值传递和引用传递,最好不用指针传递,更好地利用编译器的类型检查,使得我们有更少的出错机会,以增加代码的健壮性。

这里有个特殊情况,就是对于多态的情况,如果形参是父类,而实参是子类,在进行值传递的时候,临时对象构造时只会构造父类的部分,是一个纯粹的父类对象,而不会构造子类的任何特有的部分,因为办有虚的析构函数,而没有虚的构造函数,这一点是要注意的。如果想在被调函数中通过调用虚函数获得一些子类特有的行为,这是不能实现的。

5. 从参数检查上讲。一个健壮的函数,总会对传递来的参数进行参数检查,保证输入数据的合法性,以防止对数据的破坏并且更好地控制程序按期望的方向运行,在这种情况下使用值传递比使用指针传递要安全得多,因为你不可能传一个不存在的值给值参数或引用参数,而使用指针就可能,很可能传来的是一个非法的地址(没有初始化,指向已经delete掉的对象的指针等)。所以使用值传递和引用传递会使你的代码更健壮,具体是使用引用还是使用,最简单的一个原则就是看传递的是不是内建的数据类型,对内建的数据类型优先使用值传递,而对于自定义的数据类型,特别是传递较大的对象,那么请使用引用传递。

6. 从灵活性上。无疑,指针是最灵活的,因为指针除了可以像值传递和引用传递那样传递一个特定类型的对象外,还可以传递空指针,不传递任何对象。指针的这种优点使它大有用武之地,比如标准库里的time( )函数,你可以传递一个指针给它,把时间值填到指定的地址,你也可以传递一个空指针而只要返回值。

 

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/wzhwho/archive/2010/08/29/5847216.aspx

原创粉丝点击