2017-05-05 17 views
0

是否有使用默認初始值「一次性」拉姆達與使用普通的舊成員函數有什麼區別?使用的默認初始值拉姆達VS使用成員函數

struct A 
{ 
    int i; 
    int j = [&] 
    // something non-trivial, 
    // that requires multiple 
    // statements and depends 
    // on upper data members 
    { 
     int f = 0; 
     for (int k = 0; k < i; ++k) { 
      f += k; 
     } 
     return f; 
    }(); 
    A(int k) : i(k) { ; } 
}; 

對戰:

struct A 
{ 
    int i; 
    int J() const 
    { 
     int f = 0; 
     for (int k = 0; k < i; ++k) { 
      f += k; 
     } 
     return f; 
    } 
    int j = J(); 
    A(int k) : i(k) { ; } 
}; 

唯一我看到的是第二種方法的缺點:引入A類的命名空間在這裏額外的符號J。還有其他的區別嗎?

+0

我個人使用的功能,並通過在您需要在成員初始化列表來計算的變量。否則,你依賴於人們永遠不要改變班級中變量的順序來保持它的工作。 – NathanOliver

+0

您的lambda初始化示例不能編譯。 – vordhosbn

+0

@vordhosbn:失蹤父母固定。 – Jarod42

回答

1

關於業績,沒有在GCC 7.1編譯-O3代碼沒有什麼區別。這兩個實現產生相同的程序集。

測試代碼:

int callerFunc(int init) 
{ 
    A st(init); 
    return st.j; 
} 

被編譯到:

callerFunc(int): 
     test edi, edi 
     jle  .L7 
     lea  eax, [rdi-1] 
     cmp  eax, 7 
     jbe  .L8 
     pxor xmm0, xmm0 
     mov  edx, edi 
     xor  eax, eax 
     movdqa xmm1, XMMWORD PTR .LC0[rip] 
     shr  edx, 2 
     movdqa xmm2, XMMWORD PTR .LC1[rip] 
.L5: 
     add  eax, 1 
     paddd xmm0, xmm1 
     paddd xmm1, xmm2 
     cmp  eax, edx 
     jb  .L5 
     movdqa xmm1, xmm0 
     mov  edx, edi 
     and  edx, -4 
     psrldq xmm1, 8 
     paddd xmm0, xmm1 
     movdqa xmm1, xmm0 
     cmp  edi, edx 
     psrldq xmm1, 4 
     paddd xmm0, xmm1 
     movd eax, xmm0 
     je  .L10 
.L3: 
     lea  ecx, [rdx+1] 
     add  eax, edx 
     cmp  edi, ecx 
     jle  .L1 
     add  eax, ecx 
     lea  ecx, [rdx+2] 
     cmp  edi, ecx 
     jle  .L1 
     add  eax, ecx 
     lea  ecx, [rdx+3] 
     cmp  edi, ecx 
     jle  .L1 
     add  eax, ecx 
     lea  ecx, [rdx+4] 
     cmp  edi, ecx 
     jle  .L1 
     add  eax, ecx 
     lea  ecx, [rdx+5] 
     cmp  edi, ecx 
     jle  .L1 
     add  eax, ecx 
     lea  ecx, [rdx+6] 
     cmp  edi, ecx 
     jle  .L1 
     add  eax, ecx 
     add  edx, 7 
     lea  ecx, [rax+rdx] 
     cmp  edi, edx 
     cmovg eax, ecx 
     ret 
.L7: 
     xor  eax, eax 
.L1: 
     rep ret 
.L10: 
     rep ret 
.L8: 
     xor  eax, eax 
     xor  edx, edx 
     jmp  .L3 
.LC0: 
     .long 0 
     .long 1 
     .long 2 
     .long 3 
.LC1: 
     .long 4 
     .long 4 
     .long 4 
     .long 4 
0

一些差異浮現在腦海中:

  1. 拉姆達不能超載。因此,任何繼承的類將使用相同的功能。
  2. 拉姆達讓您捕捉到默認的局部變量,這可能會導致錯誤,如果事情被重命名/重新排序。如果你明確地通過它們,這可以被減輕。雖然重新排序是很危險的方法和lambda表達式一樣,默認拉姆達捕捉更不穩定,因爲你重新排序的變量將被隱式地傳遞到拉姆達。
+2

沒有辦法以有意義的方式重載'J',因爲它在構造時被調用,並且任何虛擬的過載將不會在該點連接。 – Yakk

+1

方法遭受變量排序相同的陷阱。 – Jarod42

+0

@ Jarod42真實的,但它仍比默認捕捉風險較小,因爲重新排序瓦爾不一定傳遞到方法。 – nikaza