转⾃
⼀、主要讨论下⾯两个函数的区别:
int& at(){
return m_data_;}
int at(){
return m_data_;}
上⾯两个函数,第⼀个返回值是int的引⽤int&,第⼆个返回值是int,⼆者的区别是什么呢?
我们先⽤⼀个语句 const int& a = mymay.at(); 来分别调⽤⼀次上⾯两个函数,然后看汇编语⾔的结果。反汇编结果:
1 #int& at() 2 #{
3 # return m_data_; 4 #} 5
6 00BB6830 push ebp
7 00BB6831 mov ebp,esp 8 00BB6833 sub esp,0CCh 9 00BB6839 push ebx 10 00BB683A push esi 11 00BB683B push edi 12 00BB683C push ecx
13 00BB683D lea edi,[ebp-0CCh] 14 00BB6843 mov ecx,33h
15 00BB6848 mov eax,0CCCCCCCCh 16 00BB684D rep stos dword ptr es:[edi] 17 00BB684F pop ecx
18 00BB6850 mov dword ptr [this],ecx 19 m_data_++;
20 00BB6853 mov eax,dword ptr [this] 21 00BB6856 mov ecx,dword ptr [eax] 22 00BB6858 add ecx,1
23 00BB685B mov edx,dword ptr [this] 24 00BB685E mov dword ptr [edx],ecx 25 return m_data_;
26 #取地址this中的值5879712(m_data_的地址)到寄存器eax中,此时寄存器eax存的是m_data_的地址27 00BB6860 mov eax,dword ptr [this] 28 }
29 00BB6863 pop edi 30 00BB68 pop esi 31 00BB6865 pop ebx
32 00BB6866 mov esp,ebp 33 00BB6868 pop ebp 34 00BB6869 ret 35 36 37 38 39
40 const int& a = mymay.at(); 41 00176AA2 lea ecx,[mymay]
42 00176AA5 call MyMat::at (01716h)
43 #此时寄存器eax中的值为m_data_的地址5879712,直接将地址5879712存⼊地址a中。44 00176AAA mov dword ptr [a],eax 45 cout << a << endl; 1 #int at() 2 #{
3 # return m_data_; 4 #} 5 6
7 012B6830 push ebp
8 012B6831 mov ebp,esp 9 012B6833 sub esp,0CCh 10 012B6839 push ebx 11 012B683A push esi 12 012B683B push edi 13 012B683C push ecx
14 012B683D lea edi,[ebp-0CCh] 15 012B6843 mov ecx,33h
16 012B6848 mov eax,0CCCCCCCCh 17 012B684D rep stos dword ptr es:[edi] 18 012B684F pop ecx
19 012B6850 mov dword ptr [this],ecx 20 return m_data_;
21 #和上⾯⼀样,也是先取出m_data_的地址22 012B6853 mov eax,dword ptr [this]
23 #和上⾯不⼀样,不是直接将m_data_的地址放⼊寄存器eax中,⽽是取地址5879712中的值(m_data_=3)放⼊寄存器eax中,此时寄存器eax存的是m_data_的值(3)24 012B6856 mov eax,dword ptr [eax] 25 }
26 012B6858 pop edi 27 012B6859 pop esi 28 012B685A pop ebx
29 012B685B mov esp,ebp 30 012B685D pop ebp 31 012B685E ret 32 33 34 35 36
37 const int& a = mymay.at(); 38 008E6AA2 lea ecx,[mymay]
39 008E6AA5 call MyMat::at (08E1Bh) 40 #此时eax的值为3,将3存⼊地址ebp-24h中,41 008E6AAA mov dword ptr [ebp-24h],eax 42 #将eax的值变成ebp-24h
43 008E6AAD lea eax,[ebp-24h]
44 #将地址ebp-24h写到地址为a中,此时a代表的地址是ebp-24h45 008E6AB0 mov dword ptr [a],eax 46 cout << a << endl;
所以结论就是:
1、返回值为引⽤型(int& )的时候,返回的是地址,因为这⾥⽤的是 int& a=mymay.at(); ,所以a和m_data_指的是同⼀块地址(由寄存器eax传回的5879712)。
2、返回值不是引⽤型(int)的时候,返回的是⼀个数值。这个时候就很有意思了,编译器是先将这个数值放⼊⼀个内存中(上⾯例⼦中,该内存地址为ebp-24h),再把这个地址付给a,此时的a代表的地址是ebp-24h,和m_data_代表的地址不⼀样(m_data_代表的地址是5879712)。
3、综上两点可以看出,当返回的值不是引⽤型时,编译器会专门给返回值分配出⼀块内存的(例⼦中为ebp-24h)。
⼆、说明⼀下函数返回时,如果不是返回⼀个变量的引⽤,则⼀定会⽣成⼀个临时变量。
看下⾯的函数,返回的是t⽽不是&t,所以⼀定会有临时变量产⽣。
1 T function1(){2 T t(0);3 return t;4 }
5 T x=function1();
这⾥的过程是:1.创建命名对象t
2.拷贝构造⼀个⽆名的临时对象,并返回这个临时对象3.由临时对象拷贝构造对象x
4.T x=function1();这句语句结束时,析构临时对象
这⾥⼀共⽣成了3个对象,⼀个命名对象t,⼀个临时对象作为返回值,⼀个命名对象x。
下⾯的函数稍微复杂⼀定,它没有先定义⼀个中间变量t,看起来似乎是直接返回了⼀个临时变量。但实际上,如果不经过c++的优化,那么它并没有提⾼效率,因为它还是创建了3个对象。
1 T function2(){2 return T(0);3 }
4 T x=function2();
这⾥的过程是:1.创建⼀个⽆名对象
2.由⽆名对象拷贝构造⼀个⽆名的临时对象3.析构⽆名对象,返回临时对象4.由临时对象拷贝构造对象x
5.T x=function2()语句结束时,析构临时对象。
这⾥⼀共⽣成了3个对象,其中有2个对象都是马上被析构掉的,不能被后⾯的代码使⽤。既然是这样,那么就会有优化的余地,可以尝试着不要前⾯的两个临时变量。c++确实会做这样的优化,优化后的c++会避免匿名对象和临时对象这两个对象的⽣成,⽽直接⽣成x,这样就减少了两次对象⽣成-回收的消耗,提⾼了程序性能。
其实function1()这段代码也是会经过优化的,但因为临时对象t是⼀个命名对象,所以⼀定会被创建。存储返回值的临时对象是多余的,会被优化掉⽽不⽣成。
但是,程序员不应该依赖这种优化,因为c++不保证这种优化⼀定会做。
因篇幅问题不能全部显示,请点此查看更多更全内容
Copyright © 2019- haog.cn 版权所有 赣ICP备2024042798号-2
违法及侵权请联系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com
本站由北京市万商天勤律师事务所王兴未律师提供法律服务