C'est un peu subjectif je pense; Je ne sais pas si l'opinion sera unanime (j'ai vu beaucoup d'extraits de code où les références sont retournées).
Selon un commentaire sur cette question que je viens de poser, concernant l'initialisation des références , renvoyer une référence peut être mauvais car, [si je comprends bien], il est plus facile de manquer de la supprimer, ce qui peut entraîner des fuites de mémoire.
Cela m'inquiète, car j'ai suivi des exemples (à moins que j'imagine des choses) et l'ai fait à plusieurs endroits ... Ai-je mal compris? Est-ce mal? Si oui, à quel point le mal?
Je pense qu'en raison de mon mélange de pointeurs et de références, combiné au fait que je suis nouveau en C ++ et à une confusion totale sur ce qu'il faut utiliser quand, mes applications doivent être un enfer de fuite de mémoire ...
De plus, je comprends que l'utilisation de pointeurs intelligents / partagés est généralement acceptée comme le meilleur moyen d'éviter les fuites de mémoire.
Réponses:
En général, le renvoi d'une référence est parfaitement normal et se produit tout le temps.
Si tu veux dire:
C'est toutes sortes de mal. La pile allouée
i
disparaîtra et vous ne faites référence à rien. C'est aussi mal:Parce que maintenant, le client doit finalement faire l'étrange:
Notez que les références rvalue ne sont encore que des références, donc toutes les applications malveillantes restent les mêmes.
Si vous souhaitez allouer quelque chose qui dépasse la portée de la fonction, utilisez un pointeur intelligent (ou en général, un conteneur):
Et maintenant, le client stocke un pointeur intelligent:
Les références sont également acceptables pour accéder à des éléments dont vous savez que la durée de vie est maintenue ouverte à un niveau supérieur, par exemple:
Ici, nous savons qu'il est correct de renvoyer une référence
i_
car tout ce qui nous appelle gère la durée de vie de l'instance de classe, ili_
vivra donc au moins aussi longtemps.Et bien sûr, il n'y a rien de mal à simplement:
Si la durée de vie doit être laissée à l'appelant et que vous calculez simplement la valeur.
Résumé: vous pouvez renvoyer une référence si la durée de vie de l'objet ne se termine pas après l'appel.
la source
return new int
.Non, non, mille fois non.
Ce qui est mal, c'est de faire référence à un objet alloué dynamiquement et de perdre le pointeur d'origine. Lorsque vous
new
un objet, vous assumez l'obligation d'avoir une garantiedelete
.Mais jetez un œil à, par exemple,
operator<<
qui doit renvoyer une référence, oune fonctionnera pas.
la source
Vous devez renvoyer une référence à un objet existant qui ne disparaît pas immédiatement et où vous ne prévoyez aucun transfert de propriété.
Ne renvoyez jamais une référence à une variable locale ou à une telle, car elle ne sera pas là pour être référencée.
Vous pouvez renvoyer une référence à quelque chose d'indépendant de la fonction, que vous ne vous attendez pas à ce que la fonction appelante prenne la responsabilité de la suppression. C'est le cas pour la
operator[]
fonction typique .Si vous créez quelque chose, vous devez renvoyer une valeur ou un pointeur (normal ou intelligent). Vous pouvez renvoyer une valeur librement, car elle va dans une variable ou une expression dans la fonction appelante. Ne renvoyez jamais un pointeur sur une variable locale, car il disparaîtra.
la source
Je ne trouve pas les réponses satisfaisantes, je vais donc ajouter mes deux cents.
Analysons les cas suivants:
Utilisation erronée
C'est évidemment une erreur
Utilisation avec des variables statiques
C'est vrai, car les variables statiques existent tout au long de la durée de vie d'un programme.
Ceci est également assez courant lors de l'implémentation d'un modèle Singleton
Usage:
Les opérateurs
Les conteneurs de bibliothèque standard dépendent fortement de l'utilisation d'opérateurs qui renvoient une référence, par exemple
peut être utilisé dans les cas suivants
Accès rapide aux données internes
Il y a des moments où & peut être utilisé pour un accès rapide aux données internes
avec utilisation:
CEPENDANT, cela peut conduire à un piège comme celui-ci:
la source
true
:If((a*b) == (c*d))
Container::data()
la mise en œuvre de devrait lirereturn m_data;
Ce n'est pas mal. Comme beaucoup de choses en C ++, c'est bien s'il est utilisé correctement, mais il y a de nombreux pièges que vous devez savoir lorsque vous l'utilisez (comme retourner une référence à une variable locale).
Il y a de bonnes choses qui peuvent être réalisées avec cela (comme map [name] = "hello world")
la source
map[name] = "hello world"
?HashMap<String,Integer>
en Java? : PPas vrai. Le renvoi d'une référence n'implique pas de sémantique de propriété. C'est juste parce que vous faites cela:
... ne signifie pas que vous possédez maintenant la mémoire mentionnée par v;
Cependant, c'est un code horrible:
Si vous faites quelque chose comme ça parce que "vous n'avez pas besoin d'un pointeur sur cette instance" alors: 1) juste déréférencer le pointeur si vous avez besoin d'une référence, et 2) vous aurez éventuellement besoin du pointeur, car vous devez faire correspondre un nouveau avec une suppression, et vous avez besoin d'un pointeur pour appeler la suppression.
la source
Il y a deux cas:
référence const - bonne idée, parfois, en particulier pour les objets lourds ou les classes proxy, optimisation du compilateur
référence non constante - mauvaise idée, parfois, rompt les encapsulations
Les deux partagent le même problème - peut potentiellement pointer vers un objet détruit ...
Je recommanderais d'utiliser des pointeurs intelligents pour de nombreuses situations où vous devez renvoyer une référence / un pointeur.
Notez également ce qui suit:
Il existe une règle formelle - la norme C ++ (section 13.3.3.1.4 si vous êtes intéressé) stipule qu'un temporaire ne peut être lié qu'à une référence const - si vous essayez d'utiliser une référence non const, le compilateur doit le signaler comme une erreur.
la source
Non seulement ce n'est pas mal, c'est parfois essentiel. Par exemple, il serait impossible d'implémenter l'opérateur [] de std :: vector sans utiliser une valeur de retour de référence.
la source
operator[]
un conteneur sans utiliser de référence ... et c'est lestd::vector<bool>
cas. (Et crée un vrai gâchis dans le processus)::std::vector<bool>
vous l'avez mentionné).std::vector<T>
dans le code du modèle est cassée, siT
cela est possiblebool
, carstd::vector<bool>
a un comportement très différent des autres instanciations. C'est utile, mais il aurait dû être donné son propre nom et non une spécialisation destd::vector
.Ajout à la réponse acceptée:
Je dirais que cet exemple n'est pas correct et devrait être évité si possible. Pourquoi? Il est très facile de se retrouver avec une référence pendante .
Pour illustrer ce point avec un exemple:
entrer dans la zone de danger:
la source
la référence de retour est généralement utilisée dans la surcharge d'opérateur en C ++ pour les objets de grande taille, car le retour d'une valeur nécessite une opération de copie. (en cas de surcharge du pérateur, nous n'utilisons généralement pas le pointeur comme valeur de retour)
Mais la référence de retour peut provoquer un problème d'allocation de mémoire. Dans la mesure où une référence au résultat sera passée hors de la fonction en tant que référence à la valeur de retour, la valeur de retour ne peut pas être une variable automatique.
si vous voulez utiliser le renvoi de référence, vous pouvez utiliser un tampon d'objet statique. par exemple
de cette façon, vous pouvez utiliser le renvoi de référence en toute sécurité.
Mais vous pouvez toujours utiliser le pointeur au lieu de la référence pour renvoyer une valeur dans functiong.
la source
Je pense que l'utilisation de référence comme valeur de retour de la fonction est beaucoup plus simple que d'utiliser le pointeur comme valeur de retour de la fonction. Deuxièmement, il serait toujours sûr d'utiliser une variable statique à laquelle se réfère la valeur de retour.
la source
La meilleure chose est de créer un objet et de le passer comme paramètre de référence / pointeur à une fonction qui alloue cette variable.
Allouer un objet dans la fonction et le renvoyer comme référence ou pointeur (le pointeur est plus sûr cependant) est une mauvaise idée en raison de la libération de mémoire à la fin du bloc fonction.
la source
La fonction getPtr peut accéder à la mémoire dynamique après la suppression ou même à un objet nul. Ce qui peut provoquer de mauvaises exceptions d'accès. Au lieu de cela, getter et setter doivent être implémentés et leur taille vérifiée avant de revenir.
la source
La fonction comme lvalue (aka, retour de références non const) doit être supprimée de C ++. C'est terriblement peu intuitif. Scott Meyers voulait un min () avec ce comportement.
ce qui n'est pas vraiment une amélioration
Ce dernier est même plus logique.
Je me rends compte que la fonction lvalue est importante pour les flux de style C ++, mais il convient de souligner que les flux de style C ++ sont terribles. Je ne suis pas le seul à penser cela ... si je me souviens, Alexandrescu avait un grand article sur la façon de faire mieux, et je pense que boost a également essayé de créer une meilleure méthode d'E / S sécurisée.
la source
vector::operator[]
par exemple. Préférez-vous écrirev.setAt(i, x)
ouv[i] = x
? Ce dernier est FAR supérieur.v.setAt(i, x)
tout moment. C'est bien supérieur.Je suis tombé sur un vrai problème où il était en effet mauvais. Un développeur a essentiellement renvoyé une référence à un objet dans un vecteur. C'était mauvais !!!
Les détails complets sur lesquels j'ai écrit en janvier: http://developer-resource.blogspot.com/2009/01/pros-and-cons-of-returing-references.html
la source
À propos du code horrible:
Donc, en effet, le pointeur de mémoire a perdu après le retour. Mais si vous utilisez shared_ptr comme ça:
La mémoire n'est pas perdue après le retour et sera libérée après l'affectation.
la source