只有少數文章聲稱通過價值傳遞可以提高性能(如果函數將會複製副本)按參數值傳遞參數時的奇怪行爲
我從來沒有真正想過如何通過價值觀來實現傳值。當你這樣做的時候,棧上會發生什麼:F v = f(g(h()))?
經過一番思考後,我得出結論,我會以這樣的方式實現它,即g()返回的值是在f()期望的位置創建的。所以,基本上,沒有複製/移動構造函數調用 - f()將簡單地獲取g()返回的對象的所有權,並在執行離開f()的作用域時將其銷燬。 g()相同 - 它將獲得h()返回的對象的所有權並在返回時銷燬它。
唉,編譯器似乎不同意。下面是測試代碼:
#include <cstdio>
using std::printf;
struct H
{
H() { printf("H ctor\n"); }
~H() { printf("H dtor\n"); }
H(H const&) {}
// H(H&&) {}
// H(H const&) = default;
// H(H&&) = default;
};
H h() { return H(); }
struct G
{
G() { printf("G ctor\n"); }
~G() { printf("G dtor\n"); }
G(G const&) {}
// G(G&&) {}
// G(G const&) = default;
// G(G&&) = default;
};
G g(H) { return G(); }
struct F
{
F() { printf("F ctor\n"); }
~F() { printf("F dtor\n"); }
};
F f(G) { return F(); }
int main()
{
F v = f(g(h()));
return 0;
}
在MSVC 2015年它的產量正是我期望:
H ctor
G ctor
H dtor
F ctor
G dtor
F dtor
但如果你註釋掉的拷貝構造函數,它看起來是這樣的:
H ctor
G ctor
H dtor
F ctor
G dtor
G dtor
H dtor
F dtor
我懷疑刪除用戶提供的拷貝構造函數會導致編譯器生成移動構造函數,這反過來會導致不必要的「移動」,無論問題的大小如何,都不會消失(嘗試添加1MB數組作爲成員變量)。即編譯器更喜歡「移動」,以至於它根本沒有做任何事情而選擇它。
這似乎是一個MSVC中的錯誤,但我真的很想有人解釋(和/或證明)這裏發生了什麼。這是問題#1。
現在,如果你嘗試GCC 5.4.0輸出根本就沒有任何意義:
H ctor
G ctor
F ctor
G dtor
H dtor
F dtor
者H已到被創建的F之前被銷燬! H是g()的範圍的局部!請注意,使用構造函數在這裏對GCC沒有影響。
和MSVC一樣 - 看起來像是一個bug,但有人可以解釋/證明這裏發生了什麼嗎?這是問題#2。
真的很愚蠢的是,經過多年的C++專業工作,我遇到了類似這樣的問題......經過近四十年的編譯器仍然不能就如何傳遞值達成一致?
以防萬一 - 我知道RVO是什麼......我非常瞭解C++。但是我找不到這兩個問題的好答案 –
您使用了哪些優化級別? 「編譯器不能同意」,複製構造器ellision是*優化* - 所以不管它是否發生都是一個QOI問題(並且程序的正確性不能依賴於它)。 –
優化lvls不起作用。找不到關於cctor/mctor elision標準的任何內容,這將解釋這裏發生的事情。請注意,我們正在討論將正確類型的* rvalues *作爲參數傳遞給另一個函數 - 我預計這裏沒有任何額外的副本(或移動)... –