C++ &&


1右值引用引入的背景 
臨時對象的產生和拷貝所帶來的效率折損,一直是C++所為人詬病的問題。但是C++標准允許編譯器對於臨時對象的產生具有完全的自由度,從而發展出了CopyElision、RVO(包括NRVO)等編譯器優化技術,它們可以防止某些情況下臨時對象產生和拷貝。下面簡單地介紹一下CopyElision、RVO

 

CopyElision-----------可以防止不必要的拷貝

 

1 struct A{ 
2 A(int){} 
3 A(constA&){} 
4 }; 
5 A a=42;

上面的創建對象的過程將會分為三步

第一步:為42創建一個臨時的對象

第二部:以臨時對象為參數拷貝構造a

第三部:析構臨時對象

如果A是一個很大的類,那么臨時對象的拷貝和析構將會造成很大的內存開銷,為什么不直接將42為參數構造a,那么會省略臨時對象需要的內存,

CopyElision就是解決這個問題的

 

測試編譯器是否具有CopyElision優化功能:

手寫A類的拷貝構造函數(拷貝函數中加打印字符),如果上述沒有執行拷貝,說明編譯器支持copyelision優化技術

 

-------------------------------------------------------------------------------------------------------------------------------------------------------

RVO返回值優化技術

 

復制代碼
struct A
{
    A(int) {}
    A(const A&) {}
};
A get()
{
    return A(1);
    // tmp1(1)
}
A a=get();//tmp2
復制代碼

上述代碼中,首先會在get函數中產生一個臨時對象tmp1,之后以tmp1為參數拷貝構造返回值tmp2,在最后一句中有產生了臨時對象tmp2,之后以tmp2為參數拷貝構造a對象

RVO技術就是解決了這種返回值產生的臨時對象的拷貝和內存開銷

 

測試,同樣可以在代碼中手寫拷貝構造函數添加輸出語句進行測試,如果沒有輸出,說明編譯器支持RVO優化技術

*************************

上述兩種優化,如果編譯器都支持,雖然不會調用拷貝構造函數,但是拷貝構造函數必須有訪問權限,如果寫在private里面,編譯器會報錯

******************

除了返回值優化,你可能還聽說過一個叫具名返回值優化(NamedReturnValueOptimization,NRVO)的優化技術,從程序員的角度而言,它其實跟RVO同樣的邏輯。只是它的臨時對象具有變量名標識,例如修改上述get()函數為: 

復制代碼
1 A get()
2 {
3     A tmp(1);//#1
4 
5     return tmp;
6 }
7 A a=get();//#2
復制代碼

想想上述修改后A類型共有幾次對象構造?雖然#1處看起來有一次顯示地構造,#2處看起來也有一次顯示地構造,但如果你的編譯器支持NRVO和CopyElision,你會發現整個Aa=get();語句的執行過程,只有一次A對象的構造。如果你在get()函數return語句前打印tmp變量的地址,在Aa=get();語句后打印a的地址,你會發現兩者地址相同,這就是應用了NRVO技術的結果。 

 

復制代碼
template<typename T>
void swap(T &a,T &b)
{
    T tmp(a);
    a=b;
    b=tmp;
}
復制代碼

我們只是想交換a和b兩個對象所擁有的數據,但卻不得不使用一個臨時對象tmp備份其中一個對象,如果T類型對象擁有指向(或引用)從堆內存分配的數據,那么深拷貝所帶來的內存開銷是可以想象的。為此,C++11標准引入了右值引用,使用它可以使臨時對象的拷貝具有move語意,從而可以使臨時對象的拷貝具有淺拷貝般的效率,這樣便可以從一定程度上解決臨時對象的深度拷貝所帶來的效率折損。 

//參考  http://www.jb51.net/article/32000.htm !!!!!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM