C++中基于其他运算符实现运算符的最优性能方案
你提到用==实现!=时,生成的汇编代码和手动写M0 != that.M0 || M1 != that.M1完全一致,这是编译器优化的正常表现——编译器能识别逻辑等价的实现,自动生成最优的机器码。
针对你给出的三种operator+实现,下面逐一分析性能差异:
三种实现的细节拆解
实现1
Class operator+(Class const& a,const Class& b) { return Class(a) += b; // no rvo }
这里先通过Class(a)创建临时对象,调用+=修改后返回。由于返回的是赋值操作的结果,无法触发返回值优化(RVO),编译器需要先创建临时对象,再可能通过移动构造传递返回值,额外开销比另外两种实现大。
实现2
Class operator+(Class const& a,const Class& b) { Class c(a); c += b; return c; // rvo }
这种写法先创建局部对象c,修改后直接返回。它符合**命名返回值优化(NRVO)**的条件,编译器可以直接在调用方的内存空间构造c,完全消除返回时的拷贝或移动开销,只需要一次拷贝构造(创建c)和一次+=操作,是非常高效的实现。你计划给左参数增加右值重载的思路很合理,这样当左操作数是临时对象时,还能直接复用对象,省掉拷贝步骤。
实现3
Class operator+(Class a,const Class& b) { a += b; return a; // is there rvo here? it seems from reading cppreference it is not }
这里的参数a是按值传递的,函数入口处已经完成一次拷贝构造。返回时,a是函数参数而非局部声明的对象,不符合NRVO条件,但如果Class支持移动语义,编译器会触发移动返回优化,把a直接移动到返回值位置。不过对于左值参数,它比实现2多一次拷贝开销;只有当传入右值作为第一个参数时,参数传递会用移动构造,开销才会接近实现2。
结论:哪种最快?
绝大多数场景下,实现2的性能最优。它的开销最小,且NRVO的优化稳定可靠。
如果你的Class支持移动语义,实现3在特定场景(传入右值左操作数)下表现不错,但整体通用性和稳定性不如实现2。实现1因为无法触发RVO,性能是三者里最差的。
内容的提问来源于stack exchange,提问作者user24551355

