[英]Why is “partial RVO” not performed?
請看一下這個愚蠢的函數,它應該只說明問題並簡化實際代碼:
struct A;
A create(bool first){
A f(21), s(42);
if(first)
return f;
else
return s;
}
我理解,因為在編譯期間不清楚返回哪個對象,我們不能指望總是執行返回值優化(RVO)。
然而,人們可能期望在50%的情況下執行RVO(假設由於缺乏進一步的信息而實現true
/ false
均勻分布):只需決定RVO( first==true
或first==false
)應該是哪種情況執行並將其應用於此參數值,接受在另一種情況下必須調用復制構造函數。
然而,對於我可以得到的所有編譯器來說,這個“部分RVO”並非如此(請參閱gcc , clang和MSVC ) - 在這兩種情況下(即first==true
或first==false
)復制構造函數是使用而不是省略。
是否存在導致上述情況下“部分RVO”無效的情況,或者這是否是所有編譯器錯過優化的不太可能的情況?
完整計划:
#include <iostream>
struct A{
int val;
A(int val_):val(val_){}
A(const A&o):val(o.val){
std::cout<<"copying: "<<val<<"\n";
}
};
A create(bool first){
A f(21), s(42);
if(first)
return f;
else
return s;
}
int main(){
std::cout<<"With true: ";
create(true);
std::cout<<"With false: ";
create(false);
}
讓我們考慮如果對f
RVO會發生什么,這意味着它是直接在返回值中構造的。 如果first==true
並返回f
,那么很棒,不需要復制。 但是如果first==false
則會返回s
,所以程序會在f
的析構f
運行之前將構造s
復制到f
的頂部。 然后, f
的析構f
將運行,現在返回值是一個已被銷毀的無效對象!
如果對s
了RVO,則應用相同的參數,但現在問題發生在first==true
。
無論您選擇哪一個,在50%的情況下都可以避免復制,並在其他50%的情況下獲得未定義的行為! 這不是一個理想的優化!
為了使這項工作,必須改變局部變量的破壞順序,以便在將s
復制到該存儲器位置之前銷毀f
(反之亦然),這是一個非常危險的事情。 破壞的順序是C ++的一個基本屬性,不應該被擺弄,或者你將破壞RAII,誰知道有多少其他假設。
除了閱讀Jonathan Wakely的答案之外,我對此的看法是,總是可以為返回的對象定義移動構造函數。 如果RVO由於某種原因無法應用,那么這將比復制構造函數更受青睞,並且在我看來這是一個很好的解決方案。
像std::vector
類的東西定義了這樣的構造函數,所以你可以免費獲得它。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.