TL; DR:從無拳擊開始,然後輪廓。
堆棧分配VS盒裝分配
這也許是更明確的:
雖然語義寫作fn foo() -> Bar
意味着從被調用框架調用者幀移動Bar
,實際上,你更有可能以fn foo(__result: mut * Bar)
簽名相當於是主叫其堆棧分配空間,並傳遞到結束一個指向被調用者的指針。
這可能並不總是足以避免複製,因爲一些模式可能會阻止直接返還口寫着:
fn defeat_copy_elision() -> WithDrop {
let one = side_effectful();
if side_effectful_too() {
one
} else {
side_effects_hurt()
}
}
這裏,也沒有神奇:
- 如果編譯器使用
one
的返回槽,那麼在分支評估爲false
的情況下,它必須將one
移出然後將新的WithDrop
實例化到其中,最後銷燬one
,
- 如果編譯器在當前棧上實例化
one
,並且必須返回它,那麼它必須執行一個副本。
如果類型不需要Drop
,那就沒有問題了。
儘管有這些古怪的情況下,我建議堅持堆棧如果可能的話,除非分析顯示它會是有益的箱子的地方。
聯成員或盒裝會員
這種情況要複雜得多:
結果,這是一個非常精細的平衡。對成員進行裝箱或拆箱可能會提高代碼庫某些部分的性能,同時降低其他代碼的性能。
肯定是有沒有一個放之四海而皆準。
因此,再一次,我建議避免拳擊,直到分析揭示了它會是有益的箱子的地方。
考慮在Linux上,任何內存分配針對其存在的過程中沒有多餘的內存可能需要一個系統調用,如果在操作系統沒有備用內存可能觸發OOM殺手殺死進程,在此時它的內存被搶救並可用。簡單的malloc(1)
可能很容易要求毫秒。