簡體   English   中英

C ++:對於內置(即類似C的)類型,為什么按值傳遞通常比按引用傳遞更有效

[英]C++: Why pass-by-value is generally more efficient than pass-by-reference for built-in (i.e., C-like) types

正如標題所示

編譯器供應商通常會將引用實現為指針。 指針的大小往往與許多內置類型相同或更大。 對於這些內置類型,無論是按值還是按引用傳遞,都將傳遞相同數量的數據。 但是,在該函數中,為了獲取實際數據,您需要取消引用此內部指針。 這可以在生成的代碼中添加一條指令,並且您還將有兩個可能不在緩存中的內存位置。 差異不會太大-但可以在緊密的循環中進行測量。

編譯器供應商在內置類型上使用const引用(有時也包括非const引用)時,可以選擇不考慮const引用-所有這些都取決於編譯器在處理函數及其調用者時可以使用的信息。

對於像int,char,short和float這樣的pod類型,數據的大小與傳遞來引用實際數據的地址的大小相同(或更小)。 在引用的地址上查找值是不必要的步驟,並且會增加額外的成本。

例如,使用以下函數foobar

void foo(char& c) {...}
void bar(char c) {...}

調用foo ,根據您的平台,將按32位或64位的值傳遞地址。 foo使用c ,您將不得不查找傳入地址中保存的數據值。

調用bar ,將傳入char大小的值,並且沒有地址查找開銷。

在實踐中,C ++實現通常通過在內部傳遞一個指針來實現按引用傳遞(假定該調用未內聯)。

因此,沒有聰明的機制允許按引用傳遞更快,因為傳遞指針不會比傳遞較小的值更快。 一旦使用函數,按值傳遞也可以從更好的優化中受益。 例如:

int foo(const int &a, int *b) {
    int c = a;
    *b = 2;
    return c + a;
}

就編譯器所知, b指向a ,這稱為“別名”。 a被值傳遞,該功能可以優化到相當於*b = 2; return 2*a; *b = 2; return 2*a; 在現代CPU的指令流水線中,它更像是“開始加載,開始b存儲,等待a加載,乘以2,等待b存儲,返回”,而不是“開始加載,開始b存儲” ,等待a載入,等待b儲存,開始載入,等待a載入,將a添加到c,然后返回”,然后您開始了解為什么出現鋸齒的可能性會對性能產生重大影響。 在某些情況下,這不一定會產生巨大的影響。

當然,混疊僅在優化為某些可能的輸入改變功能效果的情況下才阻礙優化。 但是,僅僅因為您打算使用該函數是因為別名永遠不會影響結果,但這並不一定意味着編譯器可以認為它不會:有時,實際上,在您的程序中,不會發生別名,但是編譯器不會不知道 而且,不必每次都使用第二個指針參數,只要您的函數調用優化程序“看不到”的代碼,就必須假設任何引用都可能發生變化。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM