Difference between vector::begin() and std::begin()
Asked Answered
T

3

59

While iterating over a vector in c++, I noticed there is a begin() function in the standard library, and also a begin() as a member function of the vector class. What, if any, is the difference between the two, and which should be used over the other?

Example:

vector<int> numbers;
//Code to put values in my vector
for (vector<int>::iterator i = numbers.begin(); i < numbers.end(); i++)
    cout << *i << '\n';

vs:

vector<int> numbers;
//Code to put values in my vector
for (vector<int>::iterator i = std::begin(numbers); i < std::end(numbers); i++)
    cout << *i << '\n';
Thay answered 10/10, 2014 at 0:58 Comment(4)
for containers they are the same. But std::begin also works for built-in arrays, which is very useful in template functions.Kincardine
OT, but ++i is probably more efficient than i++ because the latter returns an iterator by valueAbsorptance
possible duplicate of When to use std::begin and std::end instead of container specific versionsDough
Does this answer your question? Why use non-member begin and end functions in C++11?Eparch
P
60

std::begin() was added in C++11 to make it easier to write generic code (e.g. in templates). The most obvious reason for it is that plain C-style arrays do not have methods, hence no .begin(). So you can use std::begin() with C-style arrays, as well as STL-style containers having their own begin() and end().

If you're writing code which is not a template, you can ignore std::begin(); your fellow programmers would probably find it odd if you suddenly started using it everywhere just because it's new.

Probst answered 10/10, 2014 at 1:1 Comment(8)
How about using it just because you want to be consistent?Dashing
@BenjaminLindley: I don't think this is exactly what @RalphWaldoEmerson had in mind when he said ""A foolish consistency is the hobgoblin of little minds," but I do think it would be distracting to see std::begin() used for no reason when we've done it the old way for decades. It requires more typing for no benefit.Probst
@BenjaminLindley I know you are right, and yet, I just don't want to. :( It's the same for ++it for iterators and i++ for integers. Just the way I roll.Strung
@JohnZwinck begin(vec) (thanks to ADL) is less typing than vec.begin() :)Materials
Considering that if std::begin is available, then so are range-based for loops and auto; I'd prefer to not see the 2nd version at all!Absorptance
@MattMcNabb: that's a great point, many uses of iterators are no longer needed at all in C++11.Probst
@neilKirk ++itr is better than itr++, because it doesn't need to remember the previous iterator to return. Tons of unnecessary memory usage, and memory is one of the slower things you can do millions of times. I'll admit that compilers might be able to optimize this one for you though. I also like to think of ++itr as "add then use and itr++ as use then add. The first one is conceptually simpler than the second, giving it another point. Regardless, I'd recommend using one or the other consistently. What are the benefits of changing back and forth based on the type?Bullshit
is there any time or space complexity difference?Moussorgsky
S
7

The implementation of std::begin() for vectors simply calls std::vector<T>::begin(), so there is no difference between the two in this exact case.

Where std::begin() comes into its own is in generic algorithms:

template<typename Container>
void my_algorithm(Container c) {
    using std::begin;
    using std::end;
    auto const start = begin(c);  // ADL will find the appropriate overload
    auto const finish = end(c);
    // ... rest of code ...
}
Sahaptin answered 16/2, 2016 at 12:2 Comment(0)
E
0

If your compiler optimises your code, it doesn't matter which one you use. Otherwise, you might want to use the more OOP-looking format: numbers.begin()

This code has been plugged into Quick Bench for speed measurement:

std::vector<int> arr = {0,1,2};

static void formatA(benchmark::State& state) {
  for (auto _ : state) { // Code inside this loop is measured repeatedly
    std::vector<int>::iterator itrA = arr.begin(); // arr.end();
    benchmark::DoNotOptimize(itrA);
  }
}
// Register the function as a benchmark
BENCHMARK(formatA);

static void formatB(benchmark::State& state) {
  for (auto _ : state) { // Code before the loop is not measured
    std::vector<int>::iterator itrB = begin(arr); // end(arr);
    benchmark::DoNotOptimize(itrB);
  }
}
BENCHMARK(formatB);

All compiled using STL=libstdc++ (GNU), results for begin() are as follows:

params \ cpu_time (4dp) formatA formatB Conclusion
optim = none
compiler = Clang 11.0
std = c++11
2.1914 5.1870 A is 2.4 times faster than B
optim = none
compiler = Clang 15.0
std = c++20
2.0666 2.8974 A is 1.4 times faster than B
optim = O3
compiler = Clang 11.0
std = c++11
1.1094 1.0130 roughly equivalent runtime
(equivalent assembly)
optim = O3
compiler = Clang 15.0
std = c++20
1.0093 1.0007 roughly equivalent runtime
(equivalent assembly)

Whereas for end():

params \ cpu_time (4dp) formatA formatB Conclusion
optim = none
compiler = Clang 11.0
std = c++11
2.5166 2.6341 roughly equivalent runtime
optim = none
compiler = Clang 15.0
std = c++20
2.3657 3.8461 A is 1.6 times faster than B
optim = O3
compiler = Clang 11.0
std = c++11
1.0045 1.0126 roughly equivalent runtime
(equivalent assembly)
optim = O3
compiler = Clang 15.0
std = c++20
1.0047 1.0012 roughly equivalent runtime
(equivalent assembly)

Without optimisation,
formatA callqs <std::vector<int, std::allocator<int> >::begin()> and end() respectively, while
formatB callqs <decltype (({parm#1}.begin)()) std::begin<std::vector<int, std::allocator<int> > >(std::vector<int, std::allocator<int> >&)> and end() respectively also. Time will be lost by deducing data type for formatB.

WITH optimisation, the compiler has already done the deducing, both will be using the following assembly and varies nothing else other than addresses:

mov    0x3c5b1(%rip),%rax        # 24f188 <arr>
mov    %rax,0x8(%rsp)
add    $0xffffffffffffffff,%rbx
Estabrook answered 28/3, 2023 at 6:47 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.