我知道初始化程序列表优于普通构造函数体的优点(默认构造后跟赋值,而不是构造)。
我也了解现代编译器的优化功能。
现代编译器是否足够聪明,可以将非初始化列表构造函数优化为前一种类型?如果是,是仅限于基本类型,还是包含用户定义的类型?如果没有,为什么不呢?
答案 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