Когда использовать std:: begin и std:: end вместо конкретных контейнеров

Существуют ли какие-либо общие предпочтения или правила, которые объясняют, когда вместо свободных функций std::begin и std::end?

следует использовать конкретные версии для начала и конца контейнера,

Насколько я понимаю, если функция является шаблоном, в котором тип контейнера является параметром шаблона, то следует использовать std::begin и std::end, то есть:

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

Как насчет в других сценариях, таких как стандартная/членная функция, где известен тип контейнера? По-прежнему ли лучше использовать std::begin(cont) и std::end(cont) или должны ли функции члена контейнера cont.begin() и cont.end() быть предпочтительными?

Правильно ли я полагаю, что нет никакой пользы в производительности, вызывая cont.end() over std::end(cont)?

Ответ 1

Если вы посмотрите, скажем, на определение std::begin:

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

Вы видите, что все, что он делает, ссылается на begin(). Я полагаю, что достойный компилятор будет иметь значение nil, поэтому я предполагаю, что это сводится к предпочтению. Лично я использовал бы cont.begin() и cont.end() только для того, чтобы я никому не должен был объяснять это:)

Как указывает Mooing Duck, std::begin также работает с массивами:

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

... так что это необходимо рассмотреть. Если вы не используете массивы, я бы пошел с моим предложением. Однако, если вы не уверены в том, что будет передан STL-контейнер или массив <T>, тогда std::begin() - это путь.

Ответ 2

Версия бесплатной функции является более общей, чем функция-член контейнера. Я бы использовал его, вероятно, в общем коде, где тип контейнера неизвестен раньше (и может быть массивом). В остальной части кода (т.е. Когда контейнер фиксирован и известен), я бы, вероятно, использовал c.begin() из-за инерции. Я бы ожидал, что новые текстовые книги на С++ порекомендуют версию бесплатной функции (поскольку она никогда не бывает хуже, а иногда и лучше), но это должно догнать обычное использование.

Ответ 3

Запрет некоторых оптимизаций отключить для отладки, не будет преимуществ производительности при использовании cont.begin() (или получения указателя на первый элемент или что-то еще), если кто-то не предоставит действительно странную реализацию! Практически все реализации (и, конечно, те, у которых есть STL) являются тонкостенными и расплавленными в рот компилятора.

Плюс-сторона находится в "или что-то еще" выше: тот же код работает в разных типах сбора, будь то другой из STL, или массивов, или какая-то причудливая коллекция третьей стороной, если они думают предоставить специализацию начала для этого. Даже если вы никогда не используете это, begin() достаточно хорошо известно, что должно быть хорошо знакомо.