[英]Why is Visual C++ not performing return-value optimization on the most trivial code?
[英]Why does the ternary operator prevent Return-Value Optimization?
為什么三元運算符會阻止 MSVC 中的返回值優化 (RVO)? 考慮以下完整的示例程序:
#include <iostream>
struct Example
{
Example(int) {}
Example(Example const &) { std::cout << "copy\n"; }
};
Example FunctionUsingIf(int i)
{
if (i == 1)
return Example(1);
else
return Example(2);
}
Example FunctionUsingTernaryOperator(int i)
{
return (i == 1) ? Example(1) : Example(2);
}
int main()
{
std::cout << "using if:\n";
Example obj1 = FunctionUsingIf(0);
std::cout << "using ternary operator:\n";
Example obj2 = FunctionUsingTernaryOperator(0);
}
用 VC 2013 像這樣編譯: cl /nologo /EHsc /Za /W4 /O2 stackoverflow.cpp
輸出:
using if:
using ternary operator:
copy
顯然,三元運算符以某種方式阻止了 RVO。 為什么? 為什么編譯器不夠聰明,無法看到使用三元運算符的函數與使用 if 語句的函數執行相同的操作,並相應地進行優化?
查看程序輸出,在我看來,編譯器確實在這兩種情況下都忽略了,為什么?
因為,如果沒有激活 elide,正確的輸出將是:
所以,我希望在我的屏幕上至少有 2 個“復制”輸出。 事實上,如果我執行你的程序,用 g++ 編譯,用 -fno-elide-constructor,我從每個函數中得到 2 個復制消息。
有趣的是,如果我對 clang 做同樣的事情,當函數FunctionUsingTernaryOperator(0);
時,我會收到 3 個“復制”消息FunctionUsingTernaryOperator(0);
被調用,我猜這是由於編譯器如何實現三元。 我猜它正在生成一個臨時來解決三元運算符並將這個臨時復制到 return 語句。
這個相關問題包含答案。
標准規定何時在 return 語句中允許復制或移動省略:(12.8.31)
所以基本上復制省略只發生在以下情況:
如果您的表達式不是命名對象或臨時對象,則回退到復制。
一些有趣的行為:
編輯:
我在上面留下了我的原始答案,但 Christian Hackl 在他的評論中是正確的,它沒有回答問題。
就規則而言,示例中的三元運算符產生一個臨時對象,因此 12.8.31 允許省略復制/移動。 所以從C++語言的角度來看。 當從 FunctionUsingTernaryOperator 返回時,完全允許編譯器省略副本。
現在顯然省略沒有完成。 我想唯一的原因是 Visual Studio 編譯器團隊還沒有實現它。 因為理論上他們可以,也許在未來的版本中他們會。
我可以看到它違反了關於 RVO 的一個一般規則——返回對象(應該)被定義在一個位置。
下面的代碼段滿足規則:
Example e;
e = (i == 1)? Example{1} : Example{2};
return e;
但是在下面的原始表達式中,根據 MSVC 在兩個不同的位置定義了兩個Example
對象:
return (i == 1) ? Example(1) : Example(2);
雖然這兩個片段之間的轉換對人類來說是微不足道的,但我可以想象,如果沒有專門的實現,它不會在編譯器中自動發生。 換句話說,這是一個技術上支持 RVO 但開發人員沒有意識到的極端情況。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.