C++中的比较运算符

Comparison operators in C++

本文关键字:运算符 比较 C++      更新时间:2023-10-16

关于C++中的比较运算符,我有两个问题:

  1. 循环时,两种方式中哪一种更有效(mdatamfirst_free的类型也是double*):

for (double *p = mdata; p < mfirst_free; ++p) { .. }

for (double *p = mdata; p != mfirst_free; ++p) { .. }

我猜在前面,相同的答案对所有基元类型都有效——intdouble和指针。对吧
我知道<版本更安全,因为如果我以比预期更大的指针开始,它就不会是无限循环。但是,当我确信我不会得到无效的输入时,哪个版本更有效?

  1. 在我自己的类中重写比较运算符时,是否有一些组合是最有效的,是否有最小的所需(或推荐)组合来推导其余的

让我们假设尝试保存每个处理器周期的情况——最好的选择是什么?有没有其他更优雅的?

一如既往,亲自查看并查看生成的代码。在Ubuntu 14.04上使用g++4.8,您可以获得

    movq    -16(%rbp), %rax
    movq    %rax, -32(%rbp)
    jmp .L2
.L3:
    addq    $8, -32(%rbp)
.L2:
    movq    -32(%rbp), %rax
    cmpq    -8(%rbp), %rax
    jb  .L3

    movq    -16(%rbp), %rax
    movq    %rax, -24(%rbp)
    jmp .L4
.L5:
    addq    $8, -24(%rbp)
.L4:
    movq    -24(%rbp), %rax
    cmpq    -8(%rbp), %rax
    jne .L5

正如您所看到的,唯一相关的区别是jb .L3jne .L5

因此,从性能的角度来看,我认为两者是等效的。


在回答第二个问题时,比较所需的最小值是operator<。你可以从中推断出其他一切,例如

bool operator==(const T &x, const T &y) {
    return !(x < y) && !(y < x);
}
bool operator!=(const T &x, const T &y) {
    return !(x == y);
}
bool operator>(const T &x, const T &y) {
    return y < x;
}
bool operator<=(const T &x, const T &y) {
    return !(y < x);
}
bool operator>=(const T &x, const T &y) {
    return !(x < y);
}

当然,只有当你有通常的比较语义时,这才是真的。

首先,在纯c++术语中,没有正确的答案来回答您的问题,因为标准没有指定它,它由编译器和CPU自行决定。

实际上,你在问"如果不相等则分支"指令是否比"如果较少则分支"的指令花费更少的时间。在我遇到的所有CPU中,答案都是"否"——前提是你不会因为错误的分支预测而措手不及。

据我所知,这真的没有什么区别。我相信

p != mfirst_free

会被翻译成类似的程序集

   loop        
               CMP   p mfirst_free
               BEQ   exit
              {...body...}
               B     loop
   exit

p < mfirst_free

将转换为相同的,但它将不是BEQ指令,而是BGE。执行相同数量的指令需要相同的时间。

-有多种方法可以将for循环转换为程序集,但我的观点是,据我所知,您使用的每个比较运算符都会导致相同的运行时间。-

如果计数器变量是整数或指针,则效率可能没有差异。只要变量只是增加(一),并且开始时小于或等于结束值,效果是一样的。

但是C++迭代器不一定实现operator<。事实上,只有RandomAccessIterator需要这样做(请参阅http://en.cppreference.com/w/cpp/iterator)。因此C++11将for(auto&& v : values)转换为for(auto it = std::begin(values); it != std::end(values); ++it)。例如,std::forward_list只有ForwardIterators,因此operator<不能用于对其进行迭代

如果使用OpenMP进行并行化,则需要operator<

#pragma omp parallel for
for(auto it = std::begin(values); it < std::end(values); ++it)

因为它需要将循环拆分为更小的循环。

我想,通常情况下,最好使用operator!=与所有迭代器类型兼容,除非你做了迭代之外的其他事情(增加一个以上,等等),使用浮点值作为计数器,或者使用OpenMP。