Когда использовать 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()
достаточно хорошо известно, что должно быть хорошо знакомо.