C++ 构造函数的编译器优化
我知道初始值设定项列表比普通构造函数体(默认构造后是赋值,而不是构造)有很多优点 我还了解现代编译器的优化功能C++ 构造函数的编译器优化,c++,compiler-optimization,initializer-list,C++,Compiler Optimization,Initializer List,我知道初始值设定项列表比普通构造函数体(默认构造后是赋值,而不是构造)有很多优点 我还了解现代编译器的优化功能 现代编译器是否足够聪明,可以将非初始值设定项列表构造函数优化为前一种类型?如果是,是仅限于基本类型,还是也包括用户定义的类型?如果没有,为什么不呢?以下是gcc5.3如何使用-O2处理它。你的怀疑是正确的——在琐碎的情况下,乐观主义者弥补了草率的编程 当编译器无法查看成员变量的构造函数或赋值运算符(在本例中,因为它们是在另一个翻译单元中定义的)时,就会出现问题 当这种情况发生时,如果构
现代编译器是否足够聪明,可以将非初始值设定项列表构造函数优化为前一种类型?如果是,是仅限于基本类型,还是也包括用户定义的类型?如果没有,为什么不呢?以下是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");
}
#包括
结构条
{
条(std::string={},std::string={});
酒吧&&;
条形图和运算符=(条形图和运算符);
};
结构foo
{
__属性(noinline))
foo(int x,双y,std::string z,std::string o,std::string p)
{
a=x;
b=y;
c=z;
_bar=bar(o,p);
}
INTA;
双b;
std::字符串c;
酒吧(酒吧),;
};
结构foo2
{
__属性(noinline))
foo2(int x,双y,std::string z,std::string o,std::string p)
:a(x)、b(y)、c(标准移动(z))、u条(标准移动(o)、标准移动(p))
{
}
INTA;
双b;
std::字符串c;
酒吧(酒吧),;
};
int main()
{
foo f(45,12.2,“你好”,“foo”,“酒吧”);
foo2f2(45,12.2,“你好”,“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
.LC0:
.string“基本\u字符串::\u构造null无效”
std::\uuuCXX11::基本字符串::基本字符串(字符常量*,std::分配器常量&)[clone.isra.16]:
pushq%r13
pushq%r12
leaq 16(%rdi),%r12
pushq%rbp
pushq%rbx
subq$24,%rsp
测试质量%rsi,%rsi
movq%r12,(%rdi)
乙脑L2
movq%rdi,%rbx
movq%rsi,%rdi
movq%rsi,%r13
打电话给斯特伦
cmpq$15,%rax
movq%rax,%rbp
movq%rax,8%(rsp)
ja.L13
cmpq$1,%rax
乙脑L14
测试质量%rax,%rax
约15
.L6:
movq 8(%rsp),%rax
movq(%rbx),%rdx
movq%rax,8%(rbx)
movb$0,(%rdx,%rax)
加成24美元,rsp%
popq%rbx
popq%rbp
popq%r12
popq%r13
ret
.L13:
leaq 8(%rsp),%rsi
xorl%edx,%edx
movq%rbx,%rdi
调用std::u cxx11::基本字符串::_M_创建(无符号长&,无符号长)
movq 8(%rsp),%rdx
movq%rax,(%rbx)
movq%rax,%rdi
movq%rdx,16(%rbx)
.L4:
movq%rbp,%rdx
movq%r13,%rsi
打电话给memcpy
jmp.L6
.L14:
movzbl 0(%r13),%eax
movb%al,16%(rbx)
jmp.L6
.L2:
movl$.LC0,%edi
调用标准::\抛出\逻辑\错误(字符常量*)
.L15:
movq%r12,%rdi
jmp.L4
foo::foo(int,double,std::\uuuCXX11::basic\u字符串,std::\uuuuCXX11::basic\u字符串,std:\uuuuCXX11::basic\u字符串):
pushq%r15
pushq%r14
leaq 32(%rdi),%r14
pushq%r13
pushq%r12
leaq 48(%rdi),%r12
pushq%rbp
pushq%rbx
移动%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)
调用栏::栏(std::_cxx11::基本字符串,std:_cxx11::基本字符串)
movq 32(%rsp),%rdi
leaq 48(%rsp),%rax
cmpq%rax,%rdi
乙脑L17
呼叫操作员删除(无效*)
.L17:
movq 64(%rsp),%rdi
leaq 80(%rsp),%rax
cmpq%rax,%rdi
乙脑L18
呼叫操作员删除(无效*)
.L18:
movsd(%rsp),%xmm1
movq 8(%rsp),%rsi
leaq 16(%rbx),%rdi
移动%r15d,(%rbx)
movsd%xmm1,8(%rbx)
调用std::\uuuCXX11::基本字符串::\uM\uASSIGN(std::\uuuCXX11::基本字符串常量&)
movq 0(%rbp),%r15
leaq 80(%rsp),%rax
movq 8(%rbp),%rbp
movq%rax,64(%rsp)
movq%r15,%rax
addq%rbp,%rax
乙脑L21
测试质量%r15,%r15
约L21
movl$.LC0,%edi
调用标准::\抛出\逻辑\错误(字符常量*)
.L21:
cmpq$15,%rbp
movq%rbp,16%(rsp)
ja.L69
cmpq$1,%rbp
je.L70
xorl%edx,%edx
测试质量%rbp,%rbp
leaq 80(%rsp),%rax
约71
.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
乙脑L27
测试质量%r15,%r15
约127
movl$.LC0,%edi
调用标准::\抛出\逻辑\错误(字符常量*)
.L27:
cmpq$15,%rbp
movq%rbp,24%(rsp)
ja.L72
cmpq$1,%rbp
je.L73
xorl%eax,%eax
测试质量%rbp,%rbp
leaq 48(%rsp),%rdx
leaq 24(%rsp),%r13