2013-06-19 28 views
2

我一直在考慮對我的問題的答案,所以我不得不問,是返回類型實例還是值簡單分配?是返回類型實例還是值簡單分配

採取以下樣品例如:

class Convert { 

public: 

    int getValue (std::string const& _text); 

}; 


Convert convert; 
int total(0); 

total = convert.getValue("488"); 

THEREFOR;當從getValue()成員函數返回結果時發生了什麼,有哪些步驟?是否創建返回類型int的實例,並且是否將臨時int複製到total變量中的值,或者是直接分配給total而不需要創建臨時返回類型的返回值int

因爲我的一些代碼有void getValue (int& _result, std::string const& _text);但int getValue (std::string const& _text)更合乎邏輯。

+0

任何選項都可以根據優化進行...正如你所說的按價值回報更合乎邏輯,你應該堅持這一點..更好的方法 – sethi

回答

2

複製elision是幾乎所有編譯器支持的允許優化。

複製elision意味着在某些情況下,創建一個臨時副本,然後將該臨時副本複製到一個命名變量中,然後銷燬該臨時副本,可能會導致直接構造該變量。

與返回值優化和移動語義一起,這意味着返回可移動的複雜對象是有效的。對於類似於int的類型,as-if規則也處於運行狀態:編譯器可以執行任何表現爲 - 如果執行了代碼行或代碼塊的任何行爲,並且編譯器瞭解在複製/移動周圍(即,基本上什麼都沒有),所以他們可以跳過這些複製/移動。

爲了確保RVO和複製省略發生得當,你想要做這樣的事情:

int function() { 
    int retval = 8; // create the return value in one spot, this makes NRVO possible 
    // code goes here 
    return retval; // you can have more than one return statement in most compilers 
} 

int result = function(); // initialize the variable result by assigning the return value of the function to it. 

如果你做到以上,大多數編譯器將直接在result變量存儲構建retval對象,與沒有副本在所有如果function的身體可以在result可以看到存在的(有些人可能做到這一點,即使你看不到function mayhap體)

在C++ 11個還有其他招數。

int function() { 
    return {7}; // guaranteed to directly construct the return value without a copy 
} 

int result = function(); // even if copy elision is not done, the temporary `int` is moved into `result`. 

如果您阻止複製省略:

int function() { 
    int foo = 7; 
    int bar = 3; 
    // code 
    if (foo>bar) 
    return foo; 
    else 
    return bar; 
} 

,只要你返回一個局部變量,隱含的舉動出現。你也可以明確地將std::move納入返回值。

現在,對於像int這樣簡單小巧的類型,所有這些優化都是毫無意義的。當你在處理更大,更昂貴的對象時,如std::vectorstd::vectors,它們中的每一個都有10MB的數據,這些技術意味着返回的值最終會像傳遞指針一樣高效,以便仔細填充。

+0

謝謝雅克。我說你很瞭解編譯器!閱讀你的解釋讓我的理解顛倒了許多很好的方式。我不會猜測一個函數中具有相同類型的變量可以得到優化,從而計算直接放置在'result'變量中,而不需要臨時的。 ^^我只有一個後續問題,如你所說的「爲了確保RVO和副本的正確發生」,你有'int result = function();'在輔助調用'function()'像這樣'result = function();',沒有初始化? –

+0

@ 8-bitButterfly第二個例子將複製或移動構造。在像int這樣的簡單類型的情況下,編譯器會對構造的副本執行相同的操作,並且可以跳過以前的任何構造,因爲它知道你從來沒有讀過它。 – Yakk

0

您的全表達式total = convert.getValue("488");是一個賦值表達式。評估它將右側的值分配給變量total。右邊的值是評估子表達式convert.getValue("488");的結果。該值是int類型的臨時值(右值)。

我並不認爲有更好的方式說「評估右側結果的值分配給左側」。

優化編譯器可以很好的實現這個類是空的,是的total0初始化是不可觀測和褶皺都弄成很短。

相關問題