2014-11-24 42 views
-2

我想要實現一個更有效率的結構,當使用未命名的臨時('prvalue')作爲默認的形式參數返回大型結構時。首先,我會告訴它可以解決性能問題的例子:C++返回一個'prvalue',從一個帶有正式參數「右值」引用的函數與「prvalue」混合?

如果我們有一個結構:

struct BIG_STRUCT 
{ 
    char aArray[260]; 
    char aArray1[260]; 
} ; 

和一個函數用於初始化它的一個臨時的,然後通過這樣的值返回它:

BIG_STRUCT Func() 
{ 
    BIG_STRUCT sTemp; 

    /*init sTemp*/ 

    return sTemp; // or BIG_STRUCT(sTemp) // constructs the return value by using a temporary 
} 

我相信,現在你看到了其中性能問題是 - BIG_STRUCT 2份在棧上創建 - 1對臨時使用的爲「結構」的返回值本身的返回值和1。同樣在返回語句中,調用「複製構造函數」來使用臨時對返回值進行初始化。所以內存和執行時間都浪費了。現在你可能會想,爲什麼不通過參考返回?但是這會導致一個懸而未決的引用,因爲臨時函數在它們所屬的函數範圍的末尾被「破壞」(即使它的引用是'右值'之一也不行)。例如:

BIG_STRUCT & /* or 'rvalue' one - '&&' */ Func() 
{ 
    BIG_STRUCT sTemp; 

    /*init sTemp*/ 

    return sTemp; // return a local by reference - resulting in dangling reference 
} 

,我通過在函數調用產生的返回值暫時自己,用一位不願透露姓名的變量與類型「右值」參考默認的形式參數,並再次回到開頭所說的這個問題的解決方案對該對象的「右值」引用。所以,「BIG_STRUCT Func鍵()」的優化版本將是這樣的:

BIG_STRUCT &&Func(BIG_STRUCT &&result = BIG_STRUCT()) 
{ 
    //BIG_STRUCT sTemp; 

    /*init result*/ 

    return (BIG_STRUCT&&)result; //converts 'lvavlue' to 'xvalue' 
} 

這將工作方式相同,如果函數實際上是返回一個值,但沒有性能問題。這個構造只有一個問題,那就是函數返回一個「右值」引用,所以如果我們把它的返回值賦給「右值」引用,它的生命期不會被擴展,這會導致一個懸而未決的引用。我的意思是,新標準允許我們通過將'prvalues'生命週期分配給'rvalue'參考來擴展'prvalues'的生命週期。但是,我們沒有返回一個在當前的例子,讓這樣的代碼是無效的:

BIG_STRUCT && refPrvalue = Func(); 

refPrvalue.aArray[3] = 0; //unknown result accessing dangling reference 

任何解決方案,我怎麼能解決這個問題?

+0

它不是重複的。我正在問一個完全不同的問題。在評判之前,你介意先閱讀一下嗎? – AnArrayOfFunctions 2014-11-24 23:03:57

+1

因爲這個原因已經重新打開。 :) – hvd 2014-11-24 23:04:10

+0

如何使用填充的參考參數並使功能無效? – 2014-11-24 23:06:57

回答

1

我想你可能誤解了在C++ 11中按價值返回的原理。

使用自動存儲持續時間返回本地對象將被編譯器自動視爲右值(這是標準要求的)。

MyObject func() { 
    MyObject o; 

    return o; // Return value will be move constructed. 
} 

出現這種情況,因爲編譯器知道o龔退出作用域時被破壞。因此,在這種情況下明確地將右值傳遞給return是錯誤的,例如,

return std::move(o); // Wrong, 'o' is implicitly converted to rvalue. 

事實上,這將禁止RVO(見下一段),因此是一個悲觀。

此外, 全部 大多數現代編譯器將利用RVO(返回值優化),這將確保返回的值在呼叫站點構造。例如。

MyObject func() { 
    return {}; // Further simplification. Default constructs return value. 
} 

int main() { 
    MyObject o = func(); // You can almost be sure that no copies are made. 
         // 'o' is constructed directly at call site (RVO). 
         // Worst case scenario, one move is performed. 
} 
相關問題