从“基”运算符派生运算符 - 速度损失

Ele*_*ent 1 c++ performance operator-keyword

我的教授表示,可以从单个“基本”运算符派生出迭代器的“所有”运算符,而不会因内联而造成速度损失。

他说:

// To implement ==, != , >, <, >=, <= only only a few cases based on attrbiutes are required
// a == b       ==      !(a>b)&&!(a<b)
// a != b       ==      !(a==b)
// a < b        ==      Implemented as "actual" operator
// a > b        ==      b < a //Argument swap!
// a >= b       ==      a > b || a == b
// a <= b       ==      a < b || a == b
Run Code Online (Sandbox Code Playgroud)

与以下情况相比,不会造成速度损失:

// To implement ==, != , >, <, >=, <= only only a few cases based on attrbiutes are required
// a == b       ==      Implemented as "actual" operator
// a != b       ==      !(a==b)
// a < b        ==      Implemented as "actual" operator
// a > b        ==      Implemented as "actual" operator
// a >= b       ==      !(a < b )
// a <= b       ==      !(a > b )
Run Code Online (Sandbox Code Playgroud)

我明白,“内联”避免了函数调用以及指令和内存中的相关开销。

但是,我有点确定 -这就是问题- 评估动态逻辑语句 a la a && b && c(例如)无法优化,首先 a,然后 b,然后 c 将被评估(一旦单个语句,评估就会停止)是假的)。

因此,!(a>b)&&!(a<b)在最坏的情况下需要调用“<-code”两次。在我的直觉中,除了代码重用之外,这是一个更糟糕的实现,因为与“直接”实现“==”运算符相比,可能会出现速度损失。

这不是对错的问题——我想明白为什么他是对的

Nel*_*eal 5

您的问题似乎主要是关于实施a==bas !(a>b)&&!(a<b)。然而,两者代表的概念略有不同:平等和等价。在很多情况下,两者是相同的,但情况并非总是如此。

如果此特定数据类型的相等性和等价性相同,那么您是正确的!(a>b)&&!(a<b)a>b实现为b<a)可能需要对运算符进行两次潜在的内联调用<。但是,是什么让您确信两次呼叫接线员<比一次呼叫接线员花费更多时间==?这一切都取决于数据类型,并且您当然可以创建一个operator==operator<.

因此,假设aand的类型b是一个薄包装int(因此运算符尚未定义)。嗯,还有两件事需要考虑。首先,编译器可以生成与您编写的代码截然不同的机器代码。它可以利用许多优化,除非您查看生成的汇编代码,否则您无法准确判断一段代码的性能如何。其次,在具有流水线和其他复杂硬件系统的现代处理器中,您无法仅根据指令数量来真正预测性能。

总之,虽然您可能会说,对于简单的数据类型,“直接”实现a==b不会比实现 as 慢!(a>b)&&!(a<b),但您不能真正说它会更快。如果是的话,也很可能只是轻微的。