90 votes

Quand utiliser std::begin et std::end au lieu des versions spécifiques au conteneur ?

Existe-t-il des préférences ou des règles générales qui expliquent quand les versions spécifiques du conteneur de begin et end doivent être utilisées au lieu des fonctions libres ? std::begin et std::end ?

D'après ce que j'ai compris, si la fonction est un modèle dans lequel le type de conteneur est un paramètre de modèle, alors std::begin et std::end devrait être utilisé, 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 si les fonctions membres du conteneur cont.begin() et cont.end() être préféré ?

Ai-je raison de supposer qu'il n'y a pas d'avantage en termes de performance en appelant cont.end() sur std::end(cont) ?

74voto

La version à fonction libre 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 à l'avance (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 les nouveaux manuels sur le C++ recommandent la version à fonctions libres (car elle n'est jamais pire et parfois meilleure), mais cela doit rattraper l'usage courant.

33voto

Moo-Juice Points 22190

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 est de référencer le begin() de toute façon. Je suppose qu'un compilateur décent rendra la différence nulle, donc je suppose que c'est une question de préférence. Personnellement, j'utiliserais cont.begin() et cont.end() juste pour ne pas avoir à l'expliquer à qui que ce soit :)

Comme le souligne Mooing Duck, cependant, std::begin fonctionne également sur les tableaux :

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

... il faut donc en tenir compte. Si vous êtes pas en utilisant des tableaux, je suivrais ma suggestion. Cependant, si vous n'êtes pas sûr que ce qui est passé sera un conteneur STL, ou un tableau de <T> alors std::begin() est la voie à suivre.

10voto

Jon Hanna Points 40291

À moins que certaines optimisations ne soient désactivées pour le débogage, il n'y aura pas d'avantage en termes de performances à utiliser l'option cont.begin() (ou obtenir un pointeur sur le premier élément, ou quoi que ce soit), à moins que quelqu'un n'ait fourni une implémentation vraiment bizarre ! Presque toutes les implémentations (et certainement celles avec STL) sont très fines et fondent dans la bouche du compilateur.

Le côté positif se trouve dans le "ou quoi que ce soit" ci-dessus : Le même code fonctionne sur différents types de collections, qu'il s'agisse d'une collection de la STL, de tableaux ou d'une collection bizarre créée par un tiers s'il a pensé à fournir une spécialisation de begin pour celle-ci. Même si vous ne l'utilisez jamais, begin() est suffisamment connu pour qu'il y ait un avantage de familiarité.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X