构造函数的编译器优化

时间:2016-04-19 16:59:48

标签: c++ compiler-optimization initializer-list

我知道初始化程序列表优于普通构造函数体的优点(默认构造后跟赋值,而不是构造)。

我也了解现代编译器的优化功能。

现代编译器是否足够聪明,可以将非初始化列表构造函数优化为前一种类型?如果是,是仅限于基本类型,还是包含用户定义的类型?如果没有,为什么不呢?

1 个答案:

答案 0 :(得分:1)

以下是gcc5.3如何使用-O2处理它。你的怀疑是正确的 - 在琐碎的情况下,优化者可以弥补草率的编程。

当编译器无法看到成员变量的构造函数或赋值运算符时(在这种情况下,因为它们是在另一个转换单元中定义的),就会出现问题。

当这种情况发生时,如果构造函数写得正确,你会获得更好的代码(至少对于GCC而我怀疑与其他所有代码一样):

测试代码:

#include <string>

struct bar
{
  bar(std::string = {}, std::string = {});
  bar(bar&&);
  bar& operator=(bar&&);
};

struct foo
{
  __attribute__((noinline))
  foo(int x, double y, std::string z, std::string o, std::string p)
  {
    a = x;
    b = y;
    c = z;
    _bar = bar(o, p);
  }
  int a;
  double b;
  std::string c;
  bar _bar;
};

struct foo2
{
  __attribute__((noinline))
  foo2(int x, double y, std::string z, std::string o, std::string p)
  : a(x), b(y), c(std::move(z)), _bar(std::move(o), std::move(p))
  {
  }

  int a;
  double b;
  std::string c;
  bar _bar;
};


int main()
{
  foo f(45, 12.2, "hello", "foo", "bar");
  foo2 f2(45, 12.2, "hello", "foo", "bar");

}

示例汇编程序输出:

.LC0:
        .string "basic_string::_M_construct null not valid"
std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(char const*, std::allocator<char> const&) [clone .isra.16]:
        pushq   %r13
        pushq   %r12
        leaq    16(%rdi), %r12
        pushq   %rbp
        pushq   %rbx
        subq    $24, %rsp
        testq   %rsi, %rsi
        movq    %r12, (%rdi)
        je      .L2
        movq    %rdi, %rbx
        movq    %rsi, %rdi
        movq    %rsi, %r13
        call    strlen
        cmpq    $15, %rax
        movq    %rax, %rbp
        movq    %rax, 8(%rsp)
        ja      .L13
        cmpq    $1, %rax
        je      .L14
        testq   %rax, %rax
        jne     .L15
.L6:
        movq    8(%rsp), %rax
        movq    (%rbx), %rdx
        movq    %rax, 8(%rbx)
        movb    $0, (%rdx,%rax)
        addq    $24, %rsp
        popq    %rbx
        popq    %rbp
        popq    %r12
        popq    %r13
        ret
.L13:
        leaq    8(%rsp), %rsi
        xorl    %edx, %edx
        movq    %rbx, %rdi
        call    std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_create(unsigned long&, unsigned long)
        movq    8(%rsp), %rdx
        movq    %rax, (%rbx)
        movq    %rax, %rdi
        movq    %rdx, 16(%rbx)
.L4:
        movq    %rbp, %rdx
        movq    %r13, %rsi
        call    memcpy
        jmp     .L6
.L14:
        movzbl  0(%r13), %eax
        movb    %al, 16(%rbx)
        jmp     .L6
.L2:
        movl    $.LC0, %edi
        call    std::__throw_logic_error(char const*)
.L15:
        movq    %r12, %rdi
        jmp     .L4
foo::foo(int, double, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >):
        pushq   %r15
        pushq   %r14
        leaq    32(%rdi), %r14
        pushq   %r13
        pushq   %r12
        leaq    48(%rdi), %r12
        pushq   %rbp
        pushq   %rbx
        movl    %esi, %r15d
        movq    %rdi, %rbx
        movq    %rcx, %r13
        movq    %r8, %rbp
        subq    $104, %rsp
        movq    %r14, 16(%rdi)
        movq    $0, 24(%rdi)
        leaq    80(%rsp), %rax
        movq    %rdx, 8(%rsp)
        leaq    32(%rsp), %rsi
        leaq    64(%rsp), %rdx
        movb    $0, 32(%rdi)
        movq    %r12, %rdi
        movq    %rax, 64(%rsp)
        leaq    48(%rsp), %rax
        movsd   %xmm0, (%rsp)
        movq    $0, 72(%rsp)
        movb    $0, 80(%rsp)
        movq    %rax, 32(%rsp)
        movq    $0, 40(%rsp)
        movb    $0, 48(%rsp)
        call    bar::bar(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >)
        movq    32(%rsp), %rdi
        leaq    48(%rsp), %rax
        cmpq    %rax, %rdi
        je      .L17
        call    operator delete(void*)
.L17:
        movq    64(%rsp), %rdi
        leaq    80(%rsp), %rax
        cmpq    %rax, %rdi
        je      .L18
        call    operator delete(void*)
.L18:
        movsd   (%rsp), %xmm1
        movq    8(%rsp), %rsi
        leaq    16(%rbx), %rdi
        movl    %r15d, (%rbx)
        movsd   %xmm1, 8(%rbx)
        call    std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_assign(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)
        movq    0(%rbp), %r15
        leaq    80(%rsp), %rax
        movq    8(%rbp), %rbp
        movq    %rax, 64(%rsp)
        movq    %r15, %rax
        addq    %rbp, %rax
        je      .L21
        testq   %r15, %r15
        jne     .L21
        movl    $.LC0, %edi
        call    std::__throw_logic_error(char const*)
.L21:
        cmpq    $15, %rbp
        movq    %rbp, 16(%rsp)
        ja      .L69
        cmpq    $1, %rbp
        je      .L70
        xorl    %edx, %edx
        testq   %rbp, %rbp
        leaq    80(%rsp), %rax
        jne     .L71
.L24:
        movq    %rdx, 72(%rsp)
        movb    $0, (%rax,%rdx)
        leaq    48(%rsp), %rax
        movq    0(%r13), %r15
        movq    8(%r13), %rbp
        movq    %rax, 32(%rsp)
        movq    %r15, %rax
        addq    %rbp, %rax
        je      .L27
        testq   %r15, %r15
        jne     .L27
        movl    $.LC0, %edi
        call    std::__throw_logic_error(char const*)
.L27:
        cmpq    $15, %rbp
        movq    %rbp, 24(%rsp)
        ja      .L72
        cmpq    $1, %rbp
        je      .L73
        xorl    %eax, %eax
        testq   %rbp, %rbp
        leaq    48(%rsp), %rdx
        leaq    24(%rsp), %r13
        jne     .L74
.L30:
        movq    %rax, 40(%rsp)
        leaq    32(%rsp), %rsi
        movb    $0, (%rdx,%rax)
        leaq    64(%rsp), %rdx
        movq    %r13, %rdi
        call    bar::bar(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >)
        movq    %r13, %rsi
        movq    %r12, %rdi
        call    bar::operator=(bar&&)
        movq    32(%rsp), %rdi
        leaq    48(%rsp), %rax
        cmpq    %rax, %rdi
        je      .L31
        call    operator delete(void*)
.L31:
        movq    64(%rsp), %rdi
        leaq    80(%rsp), %rax
        cmpq    %rax, %rdi
        je      .L16
        call    operator delete(void*)
.L16:
        addq    $104, %rsp
        popq    %rbx
        popq    %rbp
        popq    %r12
        popq    %r13
        popq    %r14
        popq    %r15
        ret
.L69:
        leaq    16(%rsp), %rsi
        leaq    64(%rsp), %rdi
        xorl    %edx, %edx
        call    std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_create(unsigned long&, unsigned long)
        movq    16(%rsp), %rdx
        movq    %rax, 64(%rsp)
        movq    %rax, %rdi
        movq    %rdx, 80(%rsp)
.L22:
        movq    %rbp, %rdx
        movq    %r15, %rsi
        call    memcpy
        movq    16(%rsp), %rdx
        movq    64(%rsp), %rax
        jmp     .L24
.L72:
        leaq    24(%rsp), %r13
        leaq    32(%rsp), %rdi
        xorl    %edx, %edx
        movq    %r13, %rsi
        call    std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_create(unsigned long&, unsigned long)
        movq    24(%rsp), %rdx
        movq    %rax, 32(%rsp)
        movq    %rax, %rdi
        movq    %rdx, 48(%rsp)
.L28:
        movq    %rbp, %rdx
        movq    %r15, %rsi
        call    memcpy
        movq    24(%rsp), %rax
        movq    32(%rsp), %rdx
        jmp     .L30
.L70:
        movzbl  (%r15), %eax
        movl    $1, %edx
        movb    %al, 80(%rsp)
        leaq    80(%rsp), %rax
        jmp     .L24
.L73:
        movzbl  (%r15), %eax
        leaq    48(%rsp), %rdx
        leaq    24(%rsp), %r13
        movb    %al, 48(%rsp)
        movl    $1, %eax
        jmp     .L30
        movq    %rax, %rbp
        jmp     .L36
        movq    %rax, %rbp
        jmp     .L39
.L74:
        leaq    48(%rsp), %rdi
        leaq    24(%rsp), %r13
        jmp     .L28
.L71:
        movq    %rax, %rdi
        jmp     .L22
.L66:
        movq    %rax, %rbp
        movq    32(%rsp), %rdi
        leaq    48(%rsp), %rax
        cmpq    %rax, %rdi
        je      .L39
        call    operator delete(void*)
.L39:
        movq    64(%rsp), %rdi
        leaq    80(%rsp), %rax
        cmpq    %rax, %rdi
        je      .L36
        call    operator delete(void*)
.L36:
        movq    16(%rbx), %rdi
        cmpq    %rdi, %r14
        je      .L41
        call    operator delete(void*)
.L41:
        movq    %rbp, %rdi
        call    _Unwind_Resume
        jmp     .L66
foo2::foo2(int, double, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >):
        pushq   %r12
        pushq   %rbp
        leaq    32(%rdi), %rbp
        pushq   %rbx
        leaq    16(%rdx), %rax
        movq    %rdi, %rbx
        subq    $64, %rsp
        movl    %esi, (%rdi)
        movq    %rbp, 16(%rdi)
        movq    (%rdx), %rsi
        movsd   %xmm0, 8(%rdi)
        cmpq    %rax, %rsi
        je      .L90
        movq    %rsi, 16(%rdi)
        movq    16(%rdx), %rsi
        movq    %rsi, 32(%rdi)
.L77:
        movq    8(%rdx), %rsi
        movq    %rsi, 24(%rbx)
        movq    %rax, (%rdx)
        leaq    48(%rsp), %rax
        movq    $0, 8(%rdx)
        movb    $0, 16(%rdx)
        movq    (%r8), %rdx
        movq    %rax, 32(%rsp)
        leaq    16(%r8), %rax
        cmpq    %rax, %rdx
        je      .L91
        movq    %rdx, 32(%rsp)
        movq    16(%r8), %rdx
        movq    %rdx, 48(%rsp)
.L79:
        movq    8(%r8), %rdx
        movq    %rax, (%r8)
        leaq    16(%rsp), %rax
        movq    $0, 8(%r8)
        movb    $0, 16(%r8)
        movq    %rax, (%rsp)
        leaq    16(%rcx), %rax
        movq    %rdx, 40(%rsp)
        movq    (%rcx), %rdx
        cmpq    %rdx, %rax
        je      .L92
        movq    %rdx, (%rsp)
        movq    16(%rcx), %rdx
        movq    %rdx, 16(%rsp)
.L81:
        movq    8(%rcx), %rdx
        leaq    48(%rbx), %rdi
        movq    %rax, (%rcx)
        movq    $0, 8(%rcx)
        movb    $0, 16(%rcx)
        movq    %rsp, %rsi
        movq    %rdx, 8(%rsp)
        leaq    32(%rsp), %rdx
        call    bar::bar(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >)
        movq    (%rsp), %rdi
        leaq    16(%rsp), %rax
        cmpq    %rax, %rdi
        je      .L82
        call    operator delete(void*)
.L82:
        movq    32(%rsp), %rdi
        leaq    48(%rsp), %rax
        cmpq    %rax, %rdi
        je      .L75
        call    operator delete(void*)
.L75:
        addq    $64, %rsp
        popq    %rbx
        popq    %rbp
        popq    %r12
        ret
.L90:
        movq    16(%rdx), %rsi
        movq    24(%rdx), %rdi
        movq    %rsi, 32(%rbx)
        movq    %rdi, 40(%rbx)
        jmp     .L77
.L91:
        movq    16(%r8), %rsi
        movq    24(%r8), %rdi
        movq    %rsi, 48(%rsp)
        movq    %rdi, 56(%rsp)
        jmp     .L79
.L92:
        movq    16(%rcx), %rsi
        movq    24(%rcx), %rdi
        movq    %rsi, 16(%rsp)
        movq    %rdi, 24(%rsp)
        jmp     .L81
        movq    %rax, %r12
        movq    (%rsp), %rdi
        leaq    16(%rsp), %rax
        cmpq    %rax, %rdi
        je      .L85
        call    operator delete(void*)
.L85:
        movq    32(%rsp), %rdi
        leaq    48(%rsp), %rax
        cmpq    %rax, %rdi
        je      .L86
        call    operator delete(void*)
.L86:
        movq    16(%rbx), %rdi
        cmpq    %rdi, %rbp
        je      .L87
        call    operator delete(void*)
.L87:
        movq    %r12, %rdi
        call    _Unwind_Resume
.LC4:
        .string "bar"
.LC5:
        .string "foo"
.LC6:
        .string "hello"
main:
        pushq   %rbx
        movl    $.LC4, %esi
        subq    $224, %rsp
        leaq    160(%rsp), %rdi
        call    std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(char const*, std::allocator<char> const&) [clone .isra.16]
        leaq    64(%rsp), %rdi
        movl    $.LC5, %esi
        call    std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(char const*, std::allocator<char> const&) [clone .isra.16]
        leaq    32(%rsp), %rdi
        movl    $.LC6, %esi
        call    std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(char const*, std::allocator<char> const&) [clone .isra.16]
        leaq    160(%rsp), %r8
        leaq    64(%rsp), %rcx
        leaq    32(%rsp), %rdx
        movsd   .LC7(%rip), %xmm0
        leaq    96(%rsp), %rdi
        movl    $45, %esi
        call    foo::foo(int, double, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >)
        movq    32(%rsp), %rdi
        leaq    48(%rsp), %rax
        cmpq    %rax, %rdi
        je      .L94
        call    operator delete(void*)
.L94:
        movq    64(%rsp), %rdi
        leaq    80(%rsp), %rax
        cmpq    %rax, %rdi
        je      .L95
        call    operator delete(void*)
.L95:
        movq    160(%rsp), %rdi
        leaq    176(%rsp), %rax
        cmpq    %rax, %rdi
        je      .L96
        call    operator delete(void*)
.L96:
        leaq    64(%rsp), %rdi
        movl    $.LC4, %esi
        call    std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(char const*, std::allocator<char> const&) [clone .isra.16]
        leaq    32(%rsp), %rdi
        movl    $.LC5, %esi
        call    std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(char const*, std::allocator<char> const&) [clone .isra.16]
        movl    $.LC6, %esi
        movq    %rsp, %rdi
        call    std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(char const*, std::allocator<char> const&) [clone .isra.16]
        leaq    64(%rsp), %r8
        leaq    32(%rsp), %rcx
        leaq    160(%rsp), %rdi
        movsd   .LC7(%rip), %xmm0
        movq    %rsp, %rdx
        movl    $45, %esi
        call    foo2::foo2(int, double, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >)
        movq    (%rsp), %rdi
        leaq    16(%rsp), %rax
        cmpq    %rax, %rdi
        je      .L97
        call    operator delete(void*)
.L97:
        movq    32(%rsp), %rdi
        leaq    48(%rsp), %rax
        cmpq    %rax, %rdi
        je      .L98
        call    operator delete(void*)
.L98:
        movq    64(%rsp), %rdi
        leaq    80(%rsp), %rax
        cmpq    %rax, %rdi
        je      .L99
        call    operator delete(void*)
.L99:
        movq    176(%rsp), %rdi
        leaq    192(%rsp), %rax
        cmpq    %rax, %rdi
        je      .L100
        call    operator delete(void*)
.L100:
        movq    112(%rsp), %rdi
        leaq    128(%rsp), %rax
        cmpq    %rax, %rdi
        je      .L123
        call    operator delete(void*)
.L123:
        addq    $224, %rsp
        xorl    %eax, %eax
        popq    %rbx
        ret
        movq    %rax, %rbx
.L106:
        movq    160(%rsp), %rdi
        leaq    176(%rsp), %rdx
        cmpq    %rdx, %rdi
        je      .L115
.L125:
        call    operator delete(void*)
.L115:
        movq    %rbx, %rdi
        call    _Unwind_Resume
        movq    (%rsp), %rdi
        leaq    16(%rsp), %rdx
        movq    %rax, %rbx
        cmpq    %rdx, %rdi
        je      .L110
        call    operator delete(void*)
.L110:
        movq    32(%rsp), %rdi
        leaq    48(%rsp), %rdx
        cmpq    %rdx, %rdi
        je      .L112
        call    operator delete(void*)
.L112:
        movq    64(%rsp), %rdi
        leaq    80(%rsp), %rdx
        cmpq    %rdx, %rdi
        je      .L114
        call    operator delete(void*)
.L114:
        movq    112(%rsp), %rdi
        leaq    128(%rsp), %rdx
        cmpq    %rdx, %rdi
        jne     .L125
        jmp     .L115
        movq    %rax, %rbx
        jmp     .L110
        movq    %rax, %rbx
        jmp     .L112
        movq    %rax, %rbx
        jmp     .L114
        movq    32(%rsp), %rdi
        leaq    48(%rsp), %rdx
        movq    %rax, %rbx
        cmpq    %rdx, %rdi
        je      .L104
        call    operator delete(void*)
.L104:
        movq    64(%rsp), %rdi
        leaq    80(%rsp), %rdx
        cmpq    %rdx, %rdi
        je      .L106
        call    operator delete(void*)
        jmp     .L106
        movq    %rax, %rbx
        jmp     .L104
.LC7:
        .long   1717986918
        .long   1076389478