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

C++C++11

C++ Problem Overview


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)?

C++ Solutions


Solution 1 - C++

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.

Solution 2 - C++

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.

Solution 3 - C++

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.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionmarkView Question on Stackoverflow
Solution 1 - C++David Rodríguez - dribeasView Answer on Stackoverflow
Solution 2 - C++Moo-JuiceView Answer on Stackoverflow
Solution 3 - C++Jon HannaView Answer on Stackoverflow