Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When to use std::begin and std::end instead of container specific versions [duplicate]

Tags:

c++

c++11

Are there any general preferences or rules that explain when container specific versions of begin and end should be used instead of free functions std::begin and std::end?

It is my understanding that if the function is a template whereby the container type is a template parameter then std::begin and std::end should be used, i.e.:

template<class T> void do_stuff( const T& t )
{
    std::for_each( std::begin(t), std::end(t), /* some stuff */ );
}

What about in other scenarios such as a standard / member function where the type of container is known? Is it still better practice to use std::begin(cont) and std::end(cont) or should the container's member functions cont.begin() and cont.end() be preferred?

Am I correct in assuming that there is no benefit in performance by calling cont.end() over std::end(cont)?

like image 235
mark Avatar asked Dec 09 '11 21:12

mark


3 Answers

The free function version is more generic than the member function of the container. I would use it probably in generic code where the type of the container is not known before hand (and might be an array). In the rest of the code (i.e. when the container is fixed and known) I would probably use c.begin() due to inertia. I would expect new text books on C++ to recommend the free function version (as it is never worse and sometimes better), but that has to catch up with common usage.

like image 76
David Rodríguez - dribeas Avatar answered Nov 19 '22 19:11

David Rodríguez - dribeas


If you look at, say, the definition of std::begin:

template< class C > 
auto begin( C& c ) -> decltype(c.begin());

You see that all it does is reference the begin() anyway. I suppose a decent compiler will make the difference nil, so I guess it comes down to preference. Personally, I'd use cont.begin() and cont.end() just so that I wouldn't have to explain it to anybody :)

As Mooing Duck points out, however, std::begin also works on arrays:

template< class T, size_t N > 
T* begin( T (&array)[N] );

... so there is that to consider. If you are not using arrays, I'd go with my suggestion. However if you are unsure if what is passed is going to be an STL container, or an array of <T>, then std::begin() is the way to go.

like image 24
Moo-Juice Avatar answered Nov 19 '22 21:11

Moo-Juice


Barring some optimisations being turned off to debug, there won't be a performance benefit to using cont.begin() (or getting a pointer to the first element, or whatever) unless someone's provided a really weird implementation! Pretty much all implementations (and certainly those with STL) are wafer-thin and melt in the compiler's mouth.

The plus-side is in the "or whatever" above: The same code works across different collection types whether another from the STL, or arrays, or some bizarre collection by a third party if they thought to supply a specialisation of begin for it. Even if you never use that, begin() is well-known enough that there should be a familiarity benefit.

like image 12
Jon Hanna Avatar answered Nov 19 '22 20:11

Jon Hanna