返回值優化,是一種屬於編譯器的技術,它通過轉換源代碼和對象的創建來加快源代碼的執行速度。RVO = return value optimization。
測試平台:STM32F103VG + Keil 5.15
背景:
我們有個MacAddress::ToArray
byte* MacAddress::ToArray() const { return (byte*)&Value; }
因為封裝需要,打算返回字節數組類ByteArray的對象,於是有
ByteArray MacAddress::ToArray() const { return ByteArray((byte*)&Value, 6); }
調用代碼
ByteArray bs = mac.ToArray();
bs.CopyTo(General_reg.SHAR);
按照我淺薄的C++知識理解,在ToArray內return 的時候,會產生一次對象拷貝,到臨時對象。
然后在調用者那里的等號,產生一次拷貝構造。
實際上,編譯燒寫調試,查看反匯編
358: ByteArray bs = mac.ToArray(); 0x0800595C 4629 MOV r1,r5 0x0800595E A804 ADD r0,sp,#0x10 0x08005960 F000FE92 BL.W MacAddress::ToArray (0x08006688) 359: bs.CopyTo(General_reg.SHAR); 360: 0x08005964 2300 MOVS r3,#0x00 0x08005966 461A MOV r2,r3 0x08005968 F1040109 ADD r1,r4,#0x09 0x0800596C A804 ADD r0,sp,#0x10 0x0800596E F002FB8F BL.W Array::CopyTo (0x08008090)
直接分配內存,傳入ToArray使用。ToArray之后,並沒有見到所猜想的第二次拷貝構造。
下面看看ToArray的反匯編
0x08006688 B570 PUSH {r4-r6,lr} 0x0800668A 4605 MOV r5,r0 0x0800668C 460C MOV r4,r1 481: return ByteArray((byte*)&Value, 6); 0x0800668E 2206 MOVS r2,#0x06 0x08006690 F1040108 ADD r1,r4,#0x08 0x08006694 4628 MOV r0,r5 0x08006696 F7FFFDEB BL.W _ZN9ByteArrayC2EPKhi (0x08006270) 0x0800669A 4605 MOV r5,r0 482: } 0x0800669C BD70 POP {r4-r6,pc}
天哪!這里面只有一次構造函數,並不是猜想的那樣,先構造本地變量,然后return再拷貝。
並且,這個構造函數的內存地址,正是外部傳進去的那一個。
這個就是C++的RVO,返回值優化技術,沒想到MDK也支持。
這個技能的獲取,讓我C++水平從30%提升到40%