传值、传地址与传引用的效率分析

小y正在思考人生 2009-04-28 11:30:20
今突想起一问题,传值、传地址与传引用的效率问题

#include<windows.h>
#include<iostream>
#include<time.h>
using std::cin;
using std::cout;
using std::endl;//复杂化
//测试函数1==============
int text_1(double i,double j)
{
int delay_time=3000; //延时3s

if(i>=j)
{
Sleep(delay_time);
return i*10000;
}
else
{
Sleep(delay_time);
return j*10000;
}
}
//测试函数2==================
int text_2(double *i,double *j)
{
int delay_time=3000; //延时3s

if(*i>=*j)
{
Sleep(delay_time);
return *i*10000;
}
else
{
Sleep(delay_time);
return *j*10000;
}
}
//测试函数3======================
int text_3(double &i,double &j)
{
int delay_time=3000; //延时3s

if(i>=j)
{
Sleep(delay_time);
return i*10000;
}
else
{
Sleep(delay_time);
return j*10000;
}
}



//===========================
int main(void)
{
double num1,num2;
clock_t start,stop; //定义时钟

start = clock(); //开始时间

cout<<"Enter the num1 is ";
cin>>num1;

cout<<"Enter the num2 is ";
cin>>num2;

cout<<"The large number * 10000 is ";
cout<<text_1(num1,num2)<<" --> "<<(clock()-start)<<"ms"<<endl;
// 2) cout<<text_2(&num1,&num2)<<" --> "<<(clock()-start)<<"ms"<<endl;
// 3) cout<<text_3(num1,num2)<<" --> "<<(clock()-start)<<"ms"<<endl;

return 0;
}

测试环境VC6,本人测试的结果是,传地址>值传递>传引用(很让我奇怪)

问题 1.请大家测试执行,说出效率的结果(?>?>?)?
2.以上测试代码有没不足、错误?该测试是否真能体现该效率的问题?
3.效率分析
4.从编译原理说说该三类是怎么样执行的?
4.传值、传地址与传引用各有什么优劣?一般用于怎样的代码?
请大家各抒己见、广泛讨论,错误没关系~~



...全文
1047 42 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
42 条回复
切换为时间正序
请发表友善的回复…
发表回复
光宇广贞 2009-05-01
  • 打赏
  • 举报
回复
引用和指针对于编译器来说是一回事,没有讨论的必要。

自己看一下反汇编的代码就知道了。

一切无编译原理的编程讨论都是无意义的。
baihacker 2009-04-30
  • 打赏
  • 举报
回复
传引用,编译器有可能做优化...
传指针,首先要保证指针语义...
whhvc 2009-04-30
  • 打赏
  • 举报
回复
up
ForestDB 2009-04-29
  • 打赏
  • 举报
回复
首先,传值,传指针,传引用都是高级语言中的抽象,从比较低的层次来看,其实都是传值,换句话说,压栈的都是值(copy)。
其次,要看出差别最好用自定义类型,比如:

struct foo {
int a;
int b;
int c;
...
int x;
int y;
int z;
};

void bar(
foo x,
foo * y,
foo & z
)
{}

foo f = { 1, 2, 3, ..., 24, 25, 26, };
bar(f, &f, f);

对于foo x参数,会完全复制一份f的copy,这里时间空间都不好,
首先是空间上会占用26 * sizeof(int)的栈,然后这26 * sizeof(int)的内容入栈,需要一次小的循环(汇编里),
这里唯一的好处是是一个copy,所以对它可以放心修改。
对于foo * y参数和foo & z参数,其实从底层来看都是一样,都是&f入栈,这样在空间上只占用了栈的4个byte(一个指针的大小),时间上只是一个push调用(mov)的周期,
那么这种的问题就是在于,你通过这个指针是可以找f这个对象的,然后你就可以改动这个对象,至于这是不是你想要的结果,就看你程序的逻辑了。
zetifree 2009-04-29
  • 打赏
  • 举报
回复
[Quote=引用 30 楼 icansaymyabc 的回复:]
传值、传地址与传引用的效率无需编程验证。

1 传地址与传引用只是概念上的差别,底层实现是一样的,也就是说编出来的机器码都一模一样。

2 对于简单数据类型, char、short、int、float ,传值比传引用快了1倍都不止。对于较大的基本数据 __int64、double ,传值比传引用稍快1点点可以忽略。对于结构超过 double 的,在结构所有成员都被利用到的情况下,尺寸越大的传引用开销越接近传值的一半。如果结构不是所有成员都被利…
[/Quote]

支持这个.综合地说,较大的数据(double以上)传引用/地址比较经济;较小的数据(int等)传值比较经济~~
liliangbao 2009-04-29
  • 打赏
  • 举报
回复
指针和引用的效率应该一样~
记得在那里看见过~
shexinwei 2009-04-29
  • 打赏
  • 举报
回复
[Quote=引用 30 楼 icansaymyabc 的回复:]
传值、传地址与传引用的效率无需编程验证。

1 传地址与传引用只是概念上的差别,底层实现是一样的,也就是说编出来的机器码都一模一样。

2 对于简单数据类型, char、short、int、float ,传值比传引用快了1倍都不止。对于较大的基本数据 __int64、double ,传值比传引用稍快1点点可以忽略。对于结构超过 double 的,在结构所有成员都被利用到的情况下,尺寸越大的传引用开销越接近传值的一半。如果结构不是所有成员都被利…
[/Quote]
顶!!!!主要是看临时对象的产生问题,再就是每个编译器对你的代码的优化程度不一样,最终结果会不同
amossavez 2009-04-28
  • 打赏
  • 举报
回复
顶,引用的效率对于传结构体,类来说绝对是高效率的!!
  • 打赏
  • 举报
回复
恩啊,传指针也有指针副本,(对基本类型)为什么效率还较高,这个副本是怎么实现的
野男孩 2009-04-28
  • 打赏
  • 举报
回复
引用类型大多是用指针实现的吧?传大结构体的话,引用的效率绝对是超过传值的。

也就是说,效率问题不是仅仅与参数传递方式有关,还与传递的数据结构有关系。

当传递的数据结构较大时,传引用和传指针的效率应该是差不多的。

写了段测试代码:

#include <iostream>
using std::cout;
using std::endl;

struct CData
{
int val[10];
};

void text_1(CData data)
{
cout<< "1: addr of data= " << &data << endl;
cout<< "3: val[0] = " << data.val[0] << endl;
}

void text_2(CData* pData)
{
cout << "2: addr of pData = " << pData << endl;
cout<< "3: val[0] = " << pData->val[0] << endl;
}

void text_3(CData& data)
{
cout<< "3: addr of data = " << &data << endl;
cout<< "3: val[0] = " << data.val[0] << endl;
}

int main()
{
CData mydata;
mydata.val[0] = 100;

cout<< "main: addr of mydata = " << &mydata.val << endl;
cout<< "main: val[0] = " << mydata.val[0] << endl;

text_1(mydata);
text_2(&mydata);
text_3(mydata);

return 0;
}


输出如下:
main: addr of mydata = 00E0FF58
main: val[0] = 100
1: addr of data= 00E0FEE0
3: val[0] = 100
2: addr of pData = 00E0FF58
3: val[0] = 100
3: addr of data = 00E0FF58
3: val[0] = 100

注意:传值方式是复制了整个CData结构,而从传指针和传引用来看,传入的实际是main中的变量mydata的地址。

从生成的汇编代码看,亦是如此。

main函数中调用text_1(mydata)的代码:

; 35 :
; 36 : text_1(mydata);

;--------------这里从stack分配了0x40个字节的空间-------------
00751 83 ec 28 sub esp, 40 ; 00000028H
00754 b9 0a 00 00 00 mov ecx, 10 ; 0000000aH
;--------------这里开始把mydata中的数据复制到新分配的空间上
00759 8d 75 d8 lea esi, DWORD PTR _mydata$[ebp]
0075c 8b fc mov edi, esp
0075e f3 a5 rep movsd
00760 e8 00 00 00 00 call ?text_1@@YAXUCData@@@Z ; text_1
00765 83 c4 28 add esp, 40 ; 00000028H


main函数中调用text_2(&mydata)的代码:

; 37 : text_2(&mydata);
;----------------------这里取mydata的地址到eax,然后把eax压栈,也就是说传入了地址------
00768 8d 45 d8 lea eax, DWORD PTR _mydata$[ebp]
0076b 50 push eax
0076c e8 00 00 00 00 call ?text_2@@YAXPAUCData@@@Z ; text_2
00771 83 c4 04 add esp, 4


main函数中调用text_3(mydata)的代码:

; 38 : text_3(mydata);
;-----------------同传指针一样,这里也是取mydata的地址到ecx,然后把ecx压栈,同样是传入了地址------
00774 8d 4d d8 lea ecx, DWORD PTR _mydata$[ebp]
00777 51 push ecx
00778 e8 00 00 00 00 call ?text_3@@YAXAAUCData@@@Z ; text_3
0077d 83 c4 04 add esp, 4

deltamaster 2009-04-28
  • 打赏
  • 举报
回复
对不同的情况,传值和传引用的效率是会不同的。
基本数据类型传值和传地址比较快,对象应该是传引用比较快,还有其他的复杂情况。
gao125210 2009-04-28
  • 打赏
  • 举报
回复
学习了
ljhiiiiiiii 2009-04-28
  • 打赏
  • 举报
回复
C++中引用的实现是依靠指针实现的,两者性能应该一样。
传值的话就看传的值的类型了,对于简单类型的值,有的编译器能优化到通过寄存器传递,那样的话性能要好于指针。
jackyjkchen 2009-04-28
  • 打赏
  • 举报
回复
这很正常,指针效率很高毋庸置疑,值传递和引用传递的开销是根据具体情况而变的,像内置整数、STL类型这类不大或对值传递做过优化的类型,值传递效率较高,而自编类型或值传递要复制大量数据的类型,引用效率高,具体参见Effective C++。
liliangbao 2009-04-28
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 lingyin55 的回复:]
单纯的clock(); 计时得到的只是一个粗略的时间,而且效率相差不大的时候,得到的时间差不明显,
而且加上每次运行的时间总有差别,所以用这种方法看效率不合适,如果真的要看传值,地址和引用效率的
差别,可以用反汇编看看汇编的代码。
[/Quote]
再说个具体的数据类型也有关系~
如:传结构体和对象~
  • 打赏
  • 举报
回复
[Quote=引用 16 楼 hairetz 的回复:]

传值产生了数据的副本。
传指针只产生32位的指针副本。
传引用虽然没有副本,但是维护引用貌似…
[/Quote]hairetz同志又开始长篇大论了~~用栈原理说说吧
liliangbao 2009-04-28
  • 打赏
  • 举报
回复
帮顶~
lingyin55 2009-04-28
  • 打赏
  • 举报
回复
4.从编译原理说说该三类是怎么样执行的?
4.传值、传地址与传引用各有什么优劣?一般用于怎样的代码?


[Quote=引用 10 楼 lingyin55 的回复:]
看看这个吧,
http://lovemelovemydogs.blog.163.com/blog/static/9778560200721012092/
[/Quote]
  • 打赏
  • 举报
回复
问题 1.请大家测试执行,说出效率的结果(?>?>?)?
2.以上测试代码有没不足、错误?该测试是否真能体现该效率的问题?
3.效率分析
4.从编译原理说说该三类是怎么样执行的?
4.传值、传地址与传引用各有什么优劣?一般用于怎样的代码?
请大家各抒己见、广泛讨论,错误没关系~~



传值产生了数据的副本。
传指针只产生32位的指针副本。
传引用虽然没有副本,但是维护引用貌似还是有消耗内存的。

lingyin55 2009-04-28
  • 打赏
  • 举报
回复
不复杂,用这两个函数测会更准确一些,就看有没有必要,可以看一下我的博客
http://blog.csdn.net/lingyin55/archive/2009/03/03/3954668.aspx

[Quote=引用 13 楼 happynesslele 的回复:]
引用 9 楼 zjl_1026_2001 的回复:
用QueryPerformanceFrequency和QueryPerformanceCounter可以得到更高的精度
楼主有兴趣可以试一下
这个我想过,但感觉会很复杂,所以我想设个延迟能时间大一点,应该也可以
[/Quote]
加载更多回复(22)

65,186

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧