pourquoi std :: initializer_list est-il souvent passé par valeur?

Dans presque tous les articles que je vois sur SO, impliquant un std::initializer_list , les gens ont tendance à passer un std::initializer_list par valeur. Selon cet article:

http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/

on devrait passer par valeur, si l’on veut faire une copie de l’object passé. Mais copier un std::initializer_list n’est pas une bonne idée, car

La copie d’une liste std::initializer_list ne copie pas les objects sous-jacents. L’existence du tableau sous-jacent n’est pas garantie après la fin de la durée de vie de l’object de liste d’initialisation d’origine.

Alors, pourquoi une instance de celle-ci est-elle souvent passée par valeur et non par, disons, const& , ce qui ne garantit pas une copie inutile?

Il est passé par valeur parce que c’est bon marché. std::initializer_list , étant un wrapper mince, est probablement implémenté sous la forme d’une paire de pointeurs, donc la copie est (presque) aussi bon marché que le passage par référence. De plus, nous n’effectuons pas réellement de copie, nous effectuons (généralement) un déplacement car dans la plupart des cas, l’argument est construit à partir d’un moment temporaire. Cependant, cela ne fera pas de différence pour la performance – déplacer deux indicateurs est aussi coûteux que de les copier.

D’autre part, l’ access aux éléments d’une copie peut être plus rapide puisque nous évitons un déréférencement supplémentaire (celui de la référence).

Probablement pour les mêmes raisons, les iterators sont presque toujours passés par valeur: copier un iterator est considéré comme “bon marché”. Dans le cas de initializer_list , il y a aussi le fait que la plupart des instances seront temporaires avec des destructeurs sortingviaux, donc le compilateur peut les construire directement où il place l’argument de la fonction, sans copie. Enfin, il y a le fait que, comme les iterators, la fonction appelée est susceptible de vouloir modifier la valeur, ce qui signifie qu’elle devrait la copier localement si elle était passée par une référence à const.

MODIFIER:

Simplement pour généraliser: la bibliothèque standard part du principe qu’il est préférable de passer les iterators, initializer_lists et les objects fonctionnels par valeur. Par conséquent, vous devez vous assurer que tous les iterators, listes d’iterators ou objects fonctionnels que vous concevez sont peu coûteux à copier, et vous devez supposer dans votre propre code qu’ils sont peu coûteux à copier. La règle traditionnelle à propos de l’utilisation des références à const, et quand utiliser la valeur, devrait probablement être modifiée pour refléter ceci:

Utilisez pass by reference to const pour les types de classe autres que les iterators, initializer_lists ou les objects fonctionnels; utilisez pass by value sinon.