簡體   English   中英

為什么我們不通過函數中的引用傳遞POD?

[英]Why do we not pass POD by reference in functions?

我一直被告知我們不應該通過參考傳遞POD。 但最近我發現一個引用實際上根本沒有內存。

那么為什么我們選擇寫:

void DoSomething(int iNumber);

代替:

void DoSomething(const int& riNumber);

是不是更有效率?

實際上在這種情況下(使用int)傳遞值可能更有效,因為只需要1個內存讀取而不是2來訪問傳遞的值。

示例(使用-O2優化):

int gl = 0;

void f1(int i)
{
    gl = i + 1;
}

void f2(const int& r)
{
    gl = r + 1;
}

int main()
{
    f1(1);

    f2(1);
}

ASM

    .file   "main.cpp"
    .text
    .p2align 2,,3
.globl __Z2f1i
    .def    __Z2f1i;    .scl    2;  .type   32; .endef
__Z2f1i:
LFB0:
    pushl   %ebp
LCFI0:
    movl    %esp, %ebp
LCFI1:
    movl    8(%ebp), %eax
    incl    %eax
    movl    %eax, _gl
    leave
    ret
LFE0:
    .p2align 2,,3
.globl __Z2f2RKi
    .def    __Z2f2RKi;  .scl    2;  .type   32; .endef
__Z2f2RKi:
LFB1:
    pushl   %ebp
LCFI2:
    movl    %esp, %ebp
LCFI3:
    movl    8(%ebp), %eax
    movl    (%eax), %eax
    incl    %eax
    movl    %eax, _gl
    leave
    ret
LFE1:
    .def    ___main;    .scl    2;  .type   32; .endef
    .p2align 2,,3
.globl _main
    .def    _main;  .scl    2;  .type   32; .endef
_main:
LFB2:
    pushl   %ebp
LCFI4:
    movl    %esp, %ebp
LCFI5:
    andl    $-16, %esp
LCFI6:
    call    ___main
    movl    $2, _gl
    xorl    %eax, %eax
    leave
    ret
LFE2:
.globl _gl
    .bss
    .align 4
_gl:
    .space 4

不通過引用傳遞POD似乎是一個太普遍的規則。 POD可能很大,並且傳遞對它的引用是值得的。 在您的特定情況下, int的大小與指針大小相同 - 如果不是所有實現在后台使用以實際實現引用。 傳遞int或引用之間沒有大小差異,但現在你有額外的間接級別的懲罰。

通過引用傳遞是偽裝通過指針。

對於小數據,可以更快地將其作為值訪問,而不是必須多次使用指針。

因為它是無意義的效率增益99.999%的時間,並且它改變了語義。 它還會阻止您傳遞常量值。 例如:

void Foo(int &i) { }
Foo(1);  // ERROR!

但這可行:

void Foo(const int &i) { }
Foo(1);

此外,它意味着該函數可以修改i的值,使其對調用者可見,這可能是一件壞事(但同樣,你當然可以采用const引用)。 它歸結為優化程序中重要的部分,並使其余代碼的語義盡可能正確。

引用實際上根本沒有內存。

不確定是誰告訴你的,但事實並非如此。

沒有正確的答案,甚至沒有明顯的普遍偏好。 在某些情況下,通過值傳遞可以更快,並且非常重要的是,可以消除副作用。 在其他情況下,通過引用傳遞可以更快,並且允許從給定函數更容易地返回信息。 這適用於POD數據類型。 請記住,結構可以是POD,因此POD之間的大小因素也會有所不同。

真正的答案是習慣
我們有一種根深蒂固的文化,試圖對我們的代碼進行宏優化(即使它很少有任何真正的區別)。 如果你能告訴我代碼傳遞的值/參考(整數)有什么不同,我會感到驚訝。

一旦你開始通過模板隱藏類型,我們再次開始使用const引用(因為復制某些類型可能很昂貴)。

現在,如果您曾詢問過通用POD,那么可能存在成本差異,因為POD會變得非常大。

如果我們改變原始值,第一個版本中有一個小優勢,我們不需要額外的標識符。

void DoSomething(int iNumber)
{
    for(;iNumber > 0; --iNumber)   // mutating iNumber
    {
       // Stuff
    }
}

// No real cost difference in code.
// Just in the amount of text we need to read to understand the code
//
void DoSomething(int const& iNumber)
{
    for(int loop = iNumber;loop > 0; --loop)   // mutating new identifier
    {
       // Stuff
    }
}

取決於你的效率意味着什么。

我們通過常量引用傳遞對象的主要原因是因為通過value執行此操作將調用對象的復制構造函數,這可能是一項昂貴的操作。

復制int是微不足道的。

不它不是。 int的示例完全相同。 當你有“更重”的物體時,這很重要。

暫無
暫無

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

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