这个指针和性能惩罚
This pointer and performance penalty
void do_something() {....}
struct dummy
{
//even I dont call this, compiler will call it fall me, they need it
void call_do_something() { this->do_something_member(); }
void do_something() {....}
};
据我所知,C++中的每个类或结构都会进行隐式调用当您想访问数据成员或成员函数时使用该指针在类中,这会给C++带来性能损失吗?
我的意思是
int main()
{
do_something(); //don't need this pointer
dummy().call_do_something(); //assume the inline is prefect
return 0;
}
call_do_something需要一个this指针来调用成员函数,但是类似C的do_something不需要这个指针,这个指针会带来吗与类C函数相比,性能会受到一些损失吗?
我没有做任何微观优化的意思,因为这会给我带来很多时间总是不能给我带来好的结果,我总是遵循"衡量,不要思考"的规则。出于好奇,我想知道这个指针是否会给表现带来惩罚。
这取决于具体情况,但通常情况下,如果启用了优化,它不会比C版本更贵。真正为this
和其他功能"付费"的唯一时间是在使用继承和虚拟函数时。除此之外,编译器足够聪明,不会在不使用它的函数中浪费时间在this
上
#include <iostream>
void globalDoStuff()
{
std::cout << "Hello world!n";
}
struct Dummy
{
void doStuff() { callGlobalDoStuff(); }
void callGlobalDoStuff() { globalDoStuff(); }
};
int main()
{
globalDoStuff();
Dummy d;
d.doStuff();
}
使用GCC优化级别O3
编译,我得到以下反汇编(去掉多余的垃圾,只显示main()
):
_main:
0000000100000dd0 pushq %rbp
0000000100000dd1 movq %rsp,%rbp
0000000100000dd4 pushq %r14
0000000100000dd6 pushq %rbx
0000000100000dd7 movq 0x0000025a(%rip),%rbx
0000000100000dde leaq 0x000000d1(%rip),%r14
0000000100000de5 movq %rbx,%rdi
0000000100000de8 movq %r14,%rsi
0000000100000deb callq 0x100000e62 # bypasses globalDoStuff() and just prints "Hello world!n"
0000000100000df0 movq %rbx,%rdi
0000000100000df3 movq %r14,%rsi
0000000100000df6 callq 0x100000e62 # bypasses globalDoStuff() and just prints "Hello world!n"
0000000100000dfb xorl %eax,%eax
0000000100000dfd popq %rbx
0000000100000dfe popq %r14
0000000100000e00 popq %rbp
0000000100000e01 ret
请注意,它完全优化了Dummy
和globalDoStuff()
,只是用globalDoStuff()
的主体替换了它。globalDoStuff()
从未被调用,也从未构造过Dummy
。相反,编译器/优化器用两个系统调用来替换该代码,以直接打印出"Hello world!n"
。教训是编译器和优化器非常聪明,一般来说,你不会为不需要的东西付费。
另一方面,假设您有一个成员函数,它操纵Dummy
的成员变量。你可能会认为,与C函数相比,这是一个惩罚,对吧?可能不会,因为C函数需要一个指向要修改的对象的指针,仔细想想,这正是this
指针的起点。
因此,与C相比,C++中的this
通常不会额外付费。虚拟函数可能会有(小)损失,因为它必须查找要调用的正确函数,但我们在这里考虑的不是这种情况。
如果你不在编译器中启用优化,那么是的,当然,可能会受到惩罚,但是。。。为什么要比较未优化的代码?
#include <iostream>
#include <stdint.h>
#include <limits.h>
struct Dummy {
uint32_t counter;
Dummy(): counter(0) {}
void do_something() {
counter++;
}
};
uint32_t counter = 0;
void do_something() { counter++; }
int main(int argc, char **argv) {
Dummy dummy;
if (argc == 1) {
for (int i = 0; i < INT_MAX - 1; i++) {
for (int j = 0; j < 1; j++) {
do_something();
}
}
} else {
for (int i = 0; i < INT_MAX - 1; i++) {
for (int j = 0; j < 1; j++) {
dummy.do_something();
}
}
counter = dummy.counter;
}
std::cout << counter << std::endl;
return 0;
}
平均运行10次gcc版本4.3.5(Debian 4.3.5-4),64位,没有任何标志:
带全局计数器:0m15.062s
带伪对象:0m21.259s
如果我像Lyth建议的那样修改代码:
#include <iostream>
#include <stdint.h>
#include <limits.h>
uint32_t counter = 0;
struct Dummy {
void do_something() {
counter++;
}
};
void do_something() { counter++; }
int main(int argc, char **argv) {
Dummy dummy;
if (argc == 1) {
for (int i = 0; i < INT_MAX; i++) {
do_something();
}
} else {
for (int i = 0; i < INT_MAX; i++) {
dummy.do_something();
}
}
std::cout << counter << std::endl;
return 0;
}
然后,奇怪的是,
带全局计数器:0m12.062s
带有伪对象:0m11.860s
- 删除一个线程上有数百万个字符串的大型哈希映射会影响另一个线程的性能
- OpenMP阵列性能较差
- 递归列出所有目录中的C++与Python与Ruby的性能
- 大小相等但成员数量不同的结构之间的性能差异
- 为什么constexpr的性能比正常表达式差
- 在类中使用随机生成器时出现性能问题
- 在main()之外初始化std::vector会导致性能下降(多线程)
- 海湾合作委员会 ARM 性能下降
- GCC 和 Clang 代码性能的巨大差异
- 在容量内调整矢量大小时的性能影响
- 了解算法的性能差异(如果以不同的编程语言实现)
- 未达到的情况会影响开关外壳性能
- QStringList vs list<shared_ptr<QString>> 性能比较C++
- 是否总是可以将使用递归编写的程序重写为不使用递归的程序C++,性能观点是什么?
- 哪种方法更好,性能明智
- C++ 特征库:引用的性能开销<>
- 与多个 for 循环与单个 for 循环 wrt 相关的性能从多映射获取数据
- 基于范围的 for 循环range_declaration中各种说明符之间的性能差异
- 这个指针和性能惩罚
- 在类中包装int的任何性能惩罚