简体   繁体   English

C ++中的比较运算符

[英]Comparison operators in C++

I've got two questions regarding comparison operators in C++: 关于C ++中的比较运算符,我有两个问题:

  1. When looping, which of two ways is more efficient (type of mdata and mfirst_free is double* , too): 循环时,两种方法中的哪一种效率更高( mdatamfirst_free类型也是double* ):

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

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

I'll guess in the advance the same answer is valid for all primitive types - int , double , and pointers. 我会事先猜测,对于所有基本类型( intdouble和指针),相同的答案都是有效的。 Right? 对?
I know < version is safer because if I somehow start with bigger pointer than expected it won't be infinite loop. 我知道<版本是更安全的,因为如果我以某种方式从比预期更大的指针开始,它将不会成为无限循环。 But, when I'm sure I won't get invalid input, which version is more efficient? 但是,当我确定不会收到无效输入时,哪个版本更有效?

  1. When overriding comparison operators in my own classes, are there some combinations that are the most efficient, and is there minimal required (or recommended) combination for deducing the rest? 在我自己的类中重写比较运算符时,是否有一些组合最有效,并且是否有最少的(或推荐的)组合来推导其余的运算符?

Let's take hypothetical situation of trying to save every processor cycle - what are the best choices? 让我们假设一种尝试节省每个处理器周期的情况-最佳选择是什么? Are there some that are others more elegant? 有一些其他的更优雅吗?

As always, see for yourself and look at the generated code. 与往常一样,亲自看看并查看生成的代码。 With g++ 4.8 on Ubuntu 14.04, you get 在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

As you can see, the only relevant difference is jb .L3 vs jne .L5 . 如您所见,唯一相关的区别是jb .L3 jne .L5jne .L5

So, I would say both are equivalent from a performance point of view. 因此,从性能的角度来看,两者都是等效的。


Answering the second question, the minimum necessary for comparison is operator< . 回答第二个问题,比较所需的最小值是operator< You can deduce everything else from this, eg 您可以由此推断出其他所有内容,例如

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);
}

Of course, this is only true if you have the usual comparison semantics. 当然,只有当您具有通常的比较语义时,这才是正确的。

First of all, in pure c++ terms there is no correct answer to your question since the standard does not specify it and it's left to the compiler and CPU's discretion. 首先,在纯c ++术语中,您的问题没有正确答案,因为该标准未指定它,而是由编译器和CPU自行决定。

In real terms you're asking whether a 'branch if not equal' instruction takes any less time than a 'branch if less' instruction. 实际上,您是在问“不相等的分支”指令是否比“不相等的分支”指令花费更少的时间。 In all CPUs I have ever encountered the answer will be 'no' - provided you don't get wrong-footed by incorrect branch prediction. 在所有我遇到过的CPU中,答案都是“否”-前提是您不会因错误的分支预测而陷入困境。

As far as I know, it really doesn't make a difference. 据我所知,这确实没有什么不同。 I believe that 我相信

p != mfirst_free

would be translated to something in assembly similar to 会被翻译成类似汇编的东西

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

while the

p < mfirst_free

would translate to the same, but instead of a BEQ instruction it would be a BGE. 会翻译成相同的内容,但不是BEQ指令,而是BGE。 Same number of instructions take would take the same amount of time to be executed. 相同数量的指令将花费相同的时间来执行。

-There are various ways to translate a for loop to assembly, but my point here is that every comparison operator that you use would lead to the same running time, as far as I know.- -有多种将for循环转换为汇编的方法,但据我所知,据我所知,您使用的每个比较运算符都会导致相同的运行时间。

If the counter variable is an integer or pointer, there is probably no difference in efficiency. 如果计数器变量是整数或指针,则效率可能没有差异。 The effect is the same as long as the variable is just being incremented (by one) and start out smaller or equal and the end value. 只要变量只是被递增(加一)并且开始时较小或等于最终值,效果是相同的。

But C++ iterators don't necessarily implement operator< . 但是C ++迭代器不一定实现operator< In fact only RandomAccessIterator are required to do so (see http://en.cppreference.com/w/cpp/iterator ). 实际上,只需要使用RandomAccessIterator即可(请参阅http://en.cppreference.com/w/cpp/iterator )。 So C++11 translates for(auto&& v : values) to for(auto it = std::begin(values); it != std::end(values); ++it) . 因此C ++ 11将for(auto&& v : values)转换for(auto it = std::begin(values); it != std::end(values); ++it) For example std::forward_list only has ForwardIterators and so operator< can't be used to iterate through it. 例如std::forward_list仅具有ForwardIterators ,因此operator<不能用于对其进行迭代。

If you use OpenMP for parallelization operator< is needed: 如果将OpenMP用于并行化operator<

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

Because it needs to split the loop into smaller loops. 因为它需要将循环拆分为较小的循环。

I guess in general it would be best to use operator!= to be compatible with all iterator types, unless you do something else than iterate (increment by more than one, etc.), use floating point values as counter, or use OpenMP. 我想通常来说,最好使用operator!=来与所有迭代器类型兼容,除非您进行除迭代之外的其他操作(增量不止一个,等等),使用浮点值作为计数器或使用OpenMP。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM