Pourquoi est-il nécessaire d'avoir std::reference_wrapper
? Où doit-il être utilisé? En quoi est-ce différent d'un simple pointeur? Comment ses performances se comparent-elles à un simple pointeur?
100
Pourquoi est-il nécessaire d'avoir std::reference_wrapper
? Où doit-il être utilisé? En quoi est-ce différent d'un simple pointeur? Comment ses performances se comparent-elles à un simple pointeur?
.
avec au lieu de->
.
ne fonctionne pas comme vous le suggérez (à moins qu'à un moment donné, la proposition de point de l'opérateur ne soit adoptée et intégrée :))get()
fonction membre ou avec sa conversion implicite vers le type sous-jacent.Réponses:
std::reference_wrapper
est utile en combinaison avec des modèles. Il enveloppe un objet en stockant un pointeur vers lui, ce qui permet la réaffectation et la copie tout en imitant sa sémantique habituelle. Il indique également à certains modèles de bibliothèque de stocker des références au lieu d'objets.Considérez les algorithmes de la STL qui copient les foncteurs: Vous pouvez éviter cette copie en passant simplement un wrapper de référence faisant référence au foncteur au lieu du foncteur lui-même:
Cela fonctionne parce que…
…
reference_wrapper
S surchargeoperator()
afin qu'ils puissent être appelés comme les objets de fonction auxquels ils font référence:… (Un) comme les références ordinaires, copier (et assigner)
reference_wrappers
ne fait qu'attribuer la pointee.Copier un wrapper de référence équivaut pratiquement à copier un pointeur, ce qui est aussi bon marché que possible. Tous les appels de fonction inhérents à son utilisation (par exemple ceux à
operator()
) doivent être simplement insérés car ce sont des one-liners.reference_wrapper
s sont créés viastd::ref
etstd::cref
:L'argument template spécifie le type et la qualification cv de l'objet référencé;
r2
fait référence à aconst int
et ne donnera qu'une référence àconst int
. Les appels à des wrappers de référence contenant desconst
foncteurs n'appelleront que desconst
fonctions membresoperator()
.Les initialiseurs Rvalue sont interdits, car les autoriser ferait plus de mal que de bien. Puisque les rvalues seraient déplacées de toute façon (et avec une élision de copie garantie même si cela est évité en partie), nous n'améliorons pas la sémantique; nous pouvons cependant introduire des pointeurs pendants, car un wrapper de référence ne prolonge pas la durée de vie du pointeur.
Interaction avec la bibliothèque
Comme mentionné précédemment, on peut ordonner
make_tuple
de stocker une référence dans le résultattuple
en passant l'argument correspondant via unreference_wrapper
:Notez que ceci diffère légèrement de
forward_as_tuple
: Ici, les rvalues comme arguments ne sont pas autorisées.std::bind
montre le même comportement: il ne copiera pas l'argument mais stockera une référence s'il s'agit d'unreference_wrapper
. Utile si cet argument (ou le foncteur!)bind
N'a pas besoin d'être copié mais reste dans la portée pendant que le -foncteur est utilisé.Différence par rapport aux pointeurs ordinaires
Il n'y a pas de niveau supplémentaire d'indirection syntaxique. Les pointeurs doivent être déréférencés pour obtenir une lvaleur vers l'objet auquel ils font référence;
reference_wrapper
s ont un opérateur de conversion implicite et peuvent être appelés comme l'objet qu'ils encapsulent.reference_wrapper
s, contrairement aux pointeurs, n'ont pas d'état nul. Ils doivent être initialisés avec une référence ou une autrereference_wrapper
.Une similitude est la sémantique de copie superficielle: les pointeurs et les
reference_wrapper
s peuvent être réaffectés.la source
std::make_tuple(std::ref(i));
supérieur d'unestd::make_tuple(&i);
certaine manière?i
, pas une référence à celui-ci.Il y a au moins deux objectifs motivants
std::reference_wrapper<T>
:Il s'agit de donner une sémantique de référence aux objets passés en paramètre de valeur aux modèles de fonctions. Par exemple, vous pouvez avoir un objet fonction volumineux que vous souhaitez transmettre et
std::for_each()
qui prend son paramètre d'objet fonction par valeur. Pour éviter de copier l'objet, vous pouvez utiliserPasser des arguments
std::reference_wrapper<T>
à unestd::bind()
expression est assez courant pour lier des arguments par référence plutôt que par valeur.Lorsque vous utilisez un
std::reference_wrapper<T>
avecstd::make_tuple()
l'élément de tuple correspondant, il devient unT&
plutôt qu'unT
:la source
fun
est un objet fonction (c'est-à-dire un objet d'une classe avec un opérateur d'appel de fonction) et non une fonction: s'ilfun
se trouve être une fonction réelle, celastd::ref(fun)
n'a aucun but et rend le code potentiellement plus lent.Une autre différence, en termes de code auto-documenté, est que l'utilisation d'un
reference_wrapper
désavoue essentiellement la propriété de l'objet. En revanche, ununique_ptr
revendique la propriété, tandis qu'un pointeur nu peut ou non être possédé (il n'est pas possible de le savoir sans regarder beaucoup de code associé):la source
reference_wrapper
est supérieur aux pointeurs bruts non seulement parce qu'il est clair qu'il n'est pas propriétaire, mais aussi parce que cela ne peut pas êtrenullptr
(sans manigances) et ainsi les utilisateurs savent qu'ils ne peuvent pas passernullptr
(sans manigances) et vous savez que vous n'êtes pas obligé de le faire vérifiez-le.Vous pouvez le considérer comme un wrapper pratique autour des références afin de pouvoir les utiliser dans des conteneurs.
C'est essentiellement une
CopyAssignable
version deT&
. Chaque fois que vous voulez une référence, mais qu'elle doit être assignable, utilisezstd::reference_wrapper<T>
ou sa fonction d'assistancestd::ref()
. Ou utilisez un pointeur.Autres bizarreries
sizeof
::Et comparaison:
la source
reference_wrapper
code trivial , le rendant identique au code qui utilise un pointeur ou une référence.std::reference_wrapper
a la garantie que l'objet n'est jamais nul. Considérez un membre de la classestd::vector<T *>
. Vous devez examiner tout le code de la classe pour voir si cet objet peut jamais stocker unnullptr
dans le vecteur, alors qu'avecstd::reference_wrapper<T>
, vous êtes assuré d'avoir des objets valides.