std :: vector reserve () et push_back () sont plus rapides que resize () et array index, pourquoi?

Je faisais un test de performance rapide sur un bloc de code

void ConvertToFloat( const std::vector& audioBlock, std::vector& out ) { const float rcpShortMax = 1.0f / (float)SHRT_MAX; out.resize( audioBlock.size() ); for( size_t i = 0; i < audioBlock.size(); i++ ) { out[i] = (float)audioBlock[i] * rcpShortMax; } } 

J’étais satisfait de la vitesse d’exécution par rapport à la mise en œuvre d’origine très naïve. Il faut un peu plus de 1 ms pour traiter 65536 échantillons audio.

Cependant, juste pour le plaisir j’ai essayé ce qui suit

 void ConvertToFloat( const std::vector& audioBlock, std::vector& out ) { const float rcpShortMax = 1.0f / (float)SHRT_MAX; out.reserve( audioBlock.size() ); for( size_t i = 0; i < audioBlock.size(); i++ ) { out.push_back( (float)audioBlock[i] * rcpShortMax ); } } 

J’espérais maintenant que cela donnerait exactement les mêmes performances que le code d’origine. Cependant, la boucle prend maintenant 900usec (c’est-à-dire que 100 usec est plus rapide que l’autre implémentation).

Quelqu’un peut-il expliquer pourquoi cela donnerait une meilleure performance? Est-ce que resize() initialise le vecteur nouvellement alloué où reserve alloue mais ne construit pas? C’est la seule chose à laquelle je peux penser.

PS ceci a été testé sur un kernel simple 2Ghz AMD Turion 64 ML-37.

Le redimensionnement initialise-t-il le vecteur nouvellement alloué là où la réserve alloue mais ne construit pas?

Oui.

Redimensionner ()

Modifie le conteneur pour qu’il ait exactement n éléments, en insérant des éléments à la fin ou en effaçant des éléments de la fin si nécessaire. Si des éléments sont insérés, ils sont des copies de t. Si n > a.size() , cette expression est équivalente à a.insert(a.end(), n - size(), t) . Si n < a.size() , cela équivaut à a.erase(a.begin() + n, a.end()) .

Réserve()

Si n est inférieur ou égal à capacity() , cet appel n'a aucun effet. Sinon, il s'agit d'une demande d'allocation de mémoire supplémentaire. Si la demande aboutit, capacity() est supérieur ou égal à n; sinon, la capacity() est inchangée. Dans les deux cas, size() est inchangé.

La mémoire sera réallouée automatiquement si plus que des éléments de capacity() - size() sont insérés dans le vecteur. La réallocation ne modifie pas la size() , ni les valeurs des éléments du vecteur. Cependant, il augmente la capacity()

Reserve provoque une réallocation manuellement. La raison principale de l’utilisation de reserve() est l’efficacité: si vous connaissez la capacité à laquelle votre vecteur doit éventuellement croître, il est généralement plus efficace d’allouer cette mémoire en une fois, plutôt que de vous fier au schéma de réallocation automatique.

Le premier code écrit dans out[i] ce qui revient à begin() + i (c’est-à-dire une addition). Le second code utilise push_back , qui écrit probablement immédiatement sur un pointeur connu équivalent à end() (c’est-à-dire sans addition). Vous pourriez probablement faire la première exécution aussi rapidement que la seconde en utilisant des iterators plutôt que l’indexation d’entiers.

Éditer: aussi pour clarifier quelques autres commentaires: le vecteur contient des floats, et construire un float est en fait un non-op (de la même manière, déclarer “float f;” n’émet pas de code, mais demande au compilateur de garder de la place pour un float la stack). Je pense donc que toute différence de performance entre resize() et reserve() pour un vecteur de flotteurs n’a pas à voir avec la construction.

 out.resize( audioBlock.size() ); 

Comme la taille de out (= 0) est inférieure à audioBlock.size() , des éléments supplémentaires sont créés et ajoutés à la fin de out . Cela crée les nouveaux éléments en appelant leur constructeur par défaut.

Reserve n’alloue que la mémoire.