Existe-t-il des préférences ou des règles générales qui expliquent quand des versions spécifiques au conteneur de début et de fin doivent être utilisées à la place des fonctions gratuites std::begin
Et std::end
?
Je crois comprendre que si la fonction est un modèle par lequel le type de conteneur est un paramètre de modèle, alors std::begin
Et std::end
Doivent être utilisés, c'est-à-dire:
template<class T> void do_stuff( const T& t )
{
std::for_each( std::begin(t), std::end(t), /* some stuff */ );
}
Qu'en est-il dans d'autres scénarios tels qu'une fonction standard/membre où le type de conteneur est connu? Est-il toujours préférable d'utiliser std::begin(cont)
et std::end(cont)
ou les fonctions membres du conteneur cont.begin()
et cont.end()
devraient-elles être préférées?
Ai-je raison de supposer qu'il n'y a aucun avantage en termes de performances en appelant cont.end()
sur std::end(cont)
?
Si vous regardez, disons, la définition de std::begin
:
template< class C >
auto begin( C& c ) -> decltype(c.begin());
Vous voyez que tout ce qu'il fait c'est référencer la begin()
de toute façon. Je suppose qu'un compilateur décent fera la différence à zéro, donc je suppose que cela revient à la préférence. Personnellement, j'utiliserais cont.begin()
et cont.end()
juste pour ne pas avoir à l'expliquer à personne :)
Comme le souligne Mooing Duck, std::begin
Fonctionne également sur les tableaux:
template< class T, size_t N >
T* begin( T (&array)[N] );
... donc il y a cela à considérer. Si vous utilisez pas des tableaux, j'irais avec ma suggestion. Cependant, si vous ne savez pas si ce qui sera passé sera un conteneur STL ou un tableau de <T>
, Alors std::begin()
est la voie à suivre.
La version de la fonction gratuite est plus générique que la fonction membre du conteneur. Je l'utiliserais probablement dans du code générique où le type du conteneur n'est pas connu au préalable (et pourrait être un tableau). Dans le reste du code (c'est-à-dire lorsque le conteneur est fixe et connu), j'utiliserais probablement c.begin()
en raison de l'inertie. Je m'attendrais à ce que de nouveaux manuels sur C++ recommandent la version de la fonction gratuite (car elle n'est jamais pire et parfois meilleure), mais cela doit rattraper l'usage courant.
À moins que certaines optimisations soient désactivées pour le débogage, il n'y aura aucun avantage en termes de performances à utiliser cont.begin()
(ou à obtenir un pointeur sur le premier élément, ou autre) à moins que quelqu'un n'ait fourni une implémentation vraiment bizarre! Presque toutes les implémentations (et certainement celles avec STL) sont minces et fondent dans la bouche du compilateur.
Le côté positif se trouve dans le "ou autre" ci-dessus: le même code fonctionne sur différents types de collections, qu'il s'agisse d'un autre de la STL, ou de tableaux, ou d'une collection bizarre d'un tiers s'ils pensaient fournir une spécialisation de début pour cela. Même si vous ne l'utilisez jamais, begin()
est suffisamment connu pour qu'il y ait un avantage de familiarité.