C++ 这是一个生动的证明,你不是在测量构造函数,而是在测量其他东西

C++ 这是一个生动的证明,你不是在测量构造函数,而是在测量其他东西,c++,performance,constructor,compiler-optimization,default-constructor,C++,Performance,Constructor,Compiler Optimization,Default Constructor,当您启用-O1优化时,for循环使用T退化为1: 测试ebx,ebx jle.L3 mov-eax,0 .L4: 添加eax,1 cmp-ebx,eax jne.L4 .L3: 对于Foo和Bar。也就是说,转化为一个平凡的for(inti=0;i

当您启用
-O1
优化时,
for
循环使用
T退化为1:

测试ebx,ebx
jle.L3
mov-eax,0
.L4:
添加eax,1
cmp-ebx,eax
jne.L4
.L3:
对于
Foo
Bar
。也就是说,转化为一个平凡的
for(inti=0;i循环

当您启用
-O2
-O3
时,它会得到完全优化

没有优化(
-O0
),您将获得以下程序集:

        mov     DWORD PTR [rbp-4], 0
.L35:
        mov     eax, DWORD PTR [rbp-4]
        cmp     eax, DWORD PTR [rbp-68]
        jge     .L34
        lea     rax, [rbp-64]
        mov     rdi, rax
        call    Foo<int>::Foo()
        lea     rax, [rbp-64]
        mov     rdi, rax
        call    Foo<int>::~Foo()
        add     DWORD PTR [rbp-4], 1
        jmp     .L35
.L34:

Bar::Bar()
推动rbp
mov rbp,rsp
副区长,16
mov QWORD PTR[rbp-8],rdi
mov rax,QWORD PTR[rbp-8]
莫夫尔迪,拉克斯
调用std::vector::vector()
不
离开
ret
正如你所看到的,它们也是一样的



1 GCC 8.3

我怀疑你认为你看到的速度差异主要是时间安排不当的副产品,这是不真实的

为了查看生成的结果,我稍微简化了代码,只留下以下内容:

#include <vector>

template <typename T>
struct Foo
{
    std::vector<T> data_;

    Foo() = default;
};

template <typename T>
struct Bar
{
    std::vector<T> data_;

    Bar() {};
};

int main() { 
    Foo<int> f;

    Bar<int> b;
}
#包括
模板
结构Foo
{
std::矢量数据;
Foo()=默认值;
};
模板
结构条
{
std::矢量数据;
Bar(){};
};
int main(){
福福;
b栏;
}
然后我把它放在这里,以便于查看生成的代码

gcc 9.2似乎为两个CTOR生成了相同的代码,在这两种情况下都是这样:

push    rbp
mov     rbp, rsp
sub     rsp, 16
mov     QWORD PTR [rbp-8], rdi
mov     rax, QWORD PTR [rbp-8]
mov     rdi, rax
call    std::vector<int, std::allocator<int> >::vector() [complete object constructor]
nop
leave
ret
push-rbp
mov rbp,rsp
副区长,16
mov QWORD PTR[rbp-8],rdi
mov rax,QWORD PTR[rbp-8]
莫夫尔迪,拉克斯
调用std::vector::vector()[完整对象构造函数]
不
离开
ret
Clang生成的代码略有不同,但(同样)这两个类的代码相同:

push    rbp
mov     rbp, rsp
sub     rsp, 16
mov     qword ptr [rbp - 8], rdi
mov     rdi, qword ptr [rbp - 8]
call    std::vector<int, std::allocator<int> >::vector() [base object constructor]
add     rsp, 16
pop     rbp
ret
push-rbp
mov rbp,rsp
副区长,16
mov qword ptr[rbp-8],rdi
mov rdi,qword ptr[rbp-8]
调用std::vector::vector()[基本对象构造函数]
加上rsp,16
流行限制性商业惯例
ret
Intel icc几乎相同,为这两个类生成以下代码:

push      rbp                                           #8.5
mov       rbp, rsp                                      #8.5
sub       rsp, 16                                       #8.5
mov       QWORD PTR [-16+rbp], rdi                      #8.5
mov       rax, QWORD PTR [-16+rbp]                      #8.5
mov       rdi, rax                                      #8.5
call      std::vector<int, std::allocator<int> >::vector() [complete object constructor]                      #8.5
leave                                                   #8.5
ret  
push rbp#8.5
mov rbp,rsp#8.5
副rsp,16#8.5
mov QWORD PTR[-16+rbp],rdi#8.5
mov rax,QWORD PTR[-16+rbp]#8.5
mov rdi,rax#8.5
调用std::vector::vector()[完整对象构造函数]#8.5
离开#8.5
ret

虽然我同意其他人的观点,即禁用优化后查看性能几乎没有什么效果,但在这种情况下,即使禁用优化(至少在这三个编译器中)也不足以获得用于构建两个类的对象的不同代码。如果有一些编译器和/或优化设置会产生不同的结果,我想我不会感到非常惊讶,但我恐怕没有足够的雄心壮志去花更多的时间去寻找它。

我怀疑你认为你看到的速度差异主要是时间差的副产品,而且不是真的

为了查看生成的结果,我稍微简化了代码,只留下以下内容:

#include <vector>

template <typename T>
struct Foo
{
    std::vector<T> data_;

    Foo() = default;
};

template <typename T>
struct Bar
{
    std::vector<T> data_;

    Bar() {};
};

int main() { 
    Foo<int> f;

    Bar<int> b;
}
#包括
模板
结构Foo
{
std::矢量数据;
Foo()=默认值;
};
模板
结构条
{
std::矢量数据;
Bar(){};
};
int main(){
福福;
b栏;
}
然后我把它放在这里,以便于查看生成的代码

gcc 9.2似乎为两个CTOR生成了相同的代码,在这两种情况下都是这样:

push    rbp
mov     rbp, rsp
sub     rsp, 16
mov     QWORD PTR [rbp-8], rdi
mov     rax, QWORD PTR [rbp-8]
mov     rdi, rax
call    std::vector<int, std::allocator<int> >::vector() [complete object constructor]
nop
leave
ret
push-rbp
mov rbp,rsp
副区长,16
mov QWORD PTR[rbp-8],rdi
mov rax,QWORD PTR[rbp-8]
莫夫尔迪,拉克斯
调用std::vector::vector()[完整对象构造函数]
不
离开
ret
Clang生成的代码略有不同,但(同样)这两个类的代码相同:

push    rbp
mov     rbp, rsp
sub     rsp, 16
mov     qword ptr [rbp - 8], rdi
mov     rdi, qword ptr [rbp - 8]
call    std::vector<int, std::allocator<int> >::vector() [base object constructor]
add     rsp, 16
pop     rbp
ret
push-rbp
mov rbp,rsp
副区长,16
mov qword ptr[rbp-8],rdi
mov rdi,qword ptr[rbp-8]
调用std::vector::vector()[基本对象构造函数]
加上rsp,16
流行限制性商业惯例
ret
Intel icc几乎相同,为这两个类生成以下代码:

push      rbp                                           #8.5
mov       rbp, rsp                                      #8.5
sub       rsp, 16                                       #8.5
mov       QWORD PTR [-16+rbp], rdi                      #8.5
mov       rax, QWORD PTR [-16+rbp]                      #8.5
mov       rdi, rax                                      #8.5
call      std::vector<int, std::allocator<int> >::vector() [complete object constructor]                      #8.5
leave                                                   #8.5
ret  
push rbp#8.5
mov rbp,rsp#8.5
副rsp,16#8.5
mov QWORD PTR[-16+rbp],rdi#8.5
mov rax,QWORD PTR[-16+rbp]#8.5
mov rdi,rax#8.5
调用std::vector::vector()[完整对象构造函数]#8.5
离开#8.5
ret

虽然我同意其他人的观点,即禁用优化后查看性能几乎没有什么效果,但在这种情况下,即使禁用优化(至少在这三个编译器中)也不足以获得用于构建两个类的对象的不同代码。如果有一些编译器和/或优化设置会产生不同的结果,我想我不会感到非常惊讶,但我恐怕没有足够的雄心壮志去花更多的时间寻找它。

使用
系统时钟
来计时不是一个好主意。@Nicolas,我对时间安排的准确性不感兴趣。我感兴趣的是,Foo可以始终比Bar有更好的性能(反之亦然)。时钟已经足够好了。你测试过优化的构建吗?否则,您的结果将毫无意义。未经优化的编译不是为性能而设计的。因此,测量未经优化的代码的性能是一种无用的娱乐形式。@n.“代词m。我想
push      rbp                                           #8.5
mov       rbp, rsp                                      #8.5
sub       rsp, 16                                       #8.5
mov       QWORD PTR [-16+rbp], rdi                      #8.5
mov       rax, QWORD PTR [-16+rbp]                      #8.5
mov       rdi, rax                                      #8.5
call      std::vector<int, std::allocator<int> >::vector() [complete object constructor]                      #8.5
leave                                                   #8.5
ret