按照你写的方式,我希望B::operator*
运行速度会稍微慢一些。这是因为“幕后”的实现A::operator*
就像:
inline A A::operator*(A* this, A b)
{
A out;
out.x = this->x * b.x;
out.y = this->y * b.y;
return out;
}
因此A
,将指向其左侧参数的指针传递给函数,同时B
必须在调用函数之前制作该参数的副本。两者都必须复制其右侧参数。
如果您使用引用编写代码并使其正确,您的代码会更好,并且可能会为A
and实现相同的代码:B
const
struct A
{
float x, y;
inline A operator*(const A& b) const
{
A out;
out.x = x * b.x;
out.y = y * b.y;
return out;
}
}
struct B
{
float x, y;
}
inline B operator*(const B& a, const B& b)
{
B out;
out.x = a.x * b.x;
out.y = a.y * b.y;
return out;
}
您仍然希望返回对象,而不是引用,因为结果实际上是临时的(您没有返回修改后的现有对象)。
附录
但是,对于两个参数的 const 传递引用,在 B 中,由于取消引用,它是否会比 A 有效地更快?
首先,当您拼出所有代码时,两者都涉及相同的取消引用。(请记住,访问成员this
意味着指针取消引用。)
但即便如此,这也取决于你的编译器有多聪明。在这种情况下,假设它查看您的结构并决定它不能将其填充到寄存器中,因为它是两个浮点数,因此它将使用指针来访问它们。因此,取消引用的指针案例(这是实现引用的方式)是您将得到的最好的。程序集看起来像这样(这是伪程序集代码):
// Setup for the function. Usually already done by the inlining.
r1 <- this
r2 <- &result
r3 <- &b
// Actual function.
r4 <- r1[0]
r4 <- r4 * r3[0]
r2[0] <- r4
r4 <- r1[4]
r4 <- r4 * r3[4]
r2[4] <- r4
这是假设一个类似 RISC 的架构(比如 ARM)。x86 可能使用更少的步骤,但无论如何它都会被指令解码器扩展到这个级别的细节。关键是它都是寄存器中指针的固定偏移量取消引用,这几乎是最快的。优化器可以尝试变得更智能并跨多个寄存器实现对象,但这种优化器很难编写。(虽然我偷偷怀疑 LLVM 类型的编译器/优化器如果result
只是一个未保留的临时对象,则可以轻松地进行优化。)
因此,由于您使用的是this
,因此您有一个隐式指针取消引用。但是如果对象在堆栈上呢?没有帮助;堆栈变量变成堆栈指针(或帧指针,如果使用)的固定偏移解引用。因此,您最终会在某处取消引用指针,除非您的编译器足够聪明,可以获取您的对象并将其分布在多个寄存器中。
随意传递-S
选项以gcc
获取最终代码的反汇编,以查看您的案例中实际发生的情况。