简体   繁体   中英

checking if a std::vector is of size zero

in vs2010 std::vector.size():

return (this->_Mylast - this->_Myfirst);

and std::vector.empty():

return (this->_Myfirst == this->_Mylast);

My question is if there is any speed different between this two functions, if you are going to check if a vector has zero elements. Minus and equal are almost the same binary operations right, so the speed is the same for both these functions?

Unless you are doing this and millions of times a second (and seriously, why would you?), it won't make a scrap of difference.

If you're really interested, check it. Set up a loop of a few million times and see how long each takes.

I think you'll find that the difference is negligible.

You would be far better off concentrating on macro-optimisation issues, such as algorithm selection, and optimising this sort of stuff for readability.

And, in any case, optimising for readability is a valid approach, and one I usually take unless there are serious performance bottlenecks. In other words, use empty() or !empty() if you're doing something based on whether or not it's empty. Any other size check (like if there's at least twelve elements in it) should use size() (obviously).

As an example of how irrelevant some micro-optimisations can be, here's some C code to ponder:

#include <stdio.h>

int main(void) {
    int i, j, k, diff;
    for (i = 0; i < 1000; i++)
        for (j = 0; j < 1000000; j++)
            //diff = (i == j);
            diff = (i - j);
    return 0;
}

When I compile that with default optimisation (a) , and run it with the time command, I get CPU times of (over five runs), with one of those lines uncommented:

diff = (i - j)     diff = (i == j)
==============     ===============
         2.488              2.216
         2.424              2.220
         2.452              2.224
         2.484              2.152
         2.464              2.152
         =====              =====
Avrgs:   2.463              2.193

Now that first option is 12% slower but there's one thing you need to understand. Even though it's slower, it still only took two seconds to do this a billion times. If you're doing it once, the difference is between 0.000000002463 seconds and 0.000000002193 seconds, not really worth the effort of optimising.

Pick your battles, target your optimisations. You can get massive speed improvements with macro-optimisation strategies.


(a) With gcc "insane" optimisation level -O3 , they both take 0.000 seconds (sometimes 0.004, but rarely - I gather there's a limit to the resolution of the time command), making the difference even more irrelevant :-)

There are two reasons for using empty() over size() for checking vector emptyness:

  • std::vector.empty() may be faster than std::vector.size() depending on implementations.

  • Using empty() for checking vector emptyness is more intutive and readable than using size() .


Reference:
Nicolai M. Josutil's:
The C++ Standard Library: A Tutorial and Reference

which states:

size()
Returns the actual number of elements of the container.

empty()
Is a shortcut for checking whether the number of elements is zero ( size()==0 ). However, empty() might be implemented more efficiently, so you should use it if possible.


Note though that to be absolutely sure of which one is faster, You will have to profile both for your enviornment.

For vector the performance is probably the same. Even if it is not the same it has same Big O complexity and the difference in speed is negligible. So it is probably more convenient to use empty if you only want to check that the vector is empty. It describes more accurately what you really want to do.

Another reason to use empty is that when you later change the container to list , it may have better Big O complexity. Because there are some std::list implementations where size has linear complexity while empty is always O(1).

Scott Meyers, in "Effective STL", recommends calling empty() instead of checking the size for all containers. The reason he gives is that empty is constant-time for all the standard containters, whereas size takes linear time in some list implementations.

If you use size and you happen to change your container later, a performance problem could arise.

So, unless checking if the container has no elements is a real bottleneck (measure first, optimize if there is a problem), use empty .

Let's stop the fabulations here:

bool empty_by_difference(int* b, int* e) {
  return (e - b) == 0;
}

bool empty_by_equality(int* b, int* e) {
  return e == b;
}

Is compiled by Clang 3.0 into the following IR:

define zeroext i1 @_Z19empty_by_differencePiS_(i32* %b, i32* %e) nounwind uwtable readnone {
  %1 = icmp eq i32* %e, %b
  ret i1 %1
}

define zeroext i1 @_Z17empty_by_equalityPiS_(i32* %b, i32* %e) nounwind uwtable readnone {
  %1 = icmp eq i32* %e, %b
  ret i1 %1
}

You may not know the IR representation, but still I think this will strike home.

So let me speculate than a benchmark is just a loss of my time, and yours.


Now, from a semantic point of view, I personally find it clearer to read if (x.empty()) than to read if (x.size() == 0) .

In the latter case:

  • my eyes have to work more: distinguishing == from != or <= or >= , ...
  • my brain has to work more: remembering than 0 is a kind of sentinel value, very different from any other value such as 1 etc...

If there is a different between empty and size its so small not even a benchmark will see it. Since size is O(1) for list starting from C++11 I think its more readable to write size then empty. But thats just my opinion:)

Minus and equal are almost the same binary operations right

Indeed, almost the same. But AFAIK boolean operators are faster than other operators.

There should be no speed difference. In fact you should see the exact same code generated for both cases. The compiler should be able to perform the following transformations:

if (vec.size() == 0)
// After inlining:
if (_Mylast - _Myfirst == 0)
// Equivalent to:
if (_Mylast == _Myfirst) // Which is the same as empty() after it is inlined

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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