0

在默认初始化程序中使用“一次性”lambda 和使用普通的旧成员函数有什么区别吗?

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) { ; }
};

我唯一看到的是第二种方法的缺点:这里将额外的符号J引入到 class 的命名空间中A。还有其他区别吗?

4

2 回答 2

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
于 2017-05-05T13:19:50.077 回答
0

我想到了几个区别:

  1. lambda 不能重载。因此,任何继承的类都将使用相同的功能。
  2. 默认情况下,lambda 允许您捕获局部变量,如果重命名/重新排序可能会导致错误。如果你明确地传递它们,这可以得到缓解。虽然重新排序对方法和 lambda 类似,但默认 lambda 捕获更不稳定,因为您重新排序的变量将隐式传递给 lambda。
于 2017-05-05T13:20:23.493 回答