Voici un exemple simplifié pour illustrer la question:
class A {};
class B
{
B(A& a) : a(a) {}
A& a;
};
class C
{
C() : b(a) {}
A a;
B b;
};
Donc B est responsable de la mise à jour d’une partie de C. J’ai analysé le code avec lint et a parlé du membre de référence: lint # 1725 . Il est question ici de prendre soin de la copie et des assignations par défaut qui sont assez justes , mais la copie et l’affectation par défaut sont également mauvaises avec les pointeurs, il ya donc peu d’avantage là-bas.
J'essaie toujours d'utiliser des références dans la mesure du possible car des pointeurs nus introduisent de manière incertaine l'identité du responsable de la suppression de ce pointeur. Je préfère incorporer des objets par valeur, mais si j'ai besoin d'un pointeur, j'utilise auto_ptr dans les données membres de la classe qui possède le pointeur et je passe l'objet comme référence.
En règle générale, je n’utiliserais un pointeur dans les données de membre que si le pointeur pouvait être nul ou pouvait changer. Existe-t-il d'autres raisons de préférer les pointeurs aux références pour les membres de données?
Est-il vrai de dire qu'un objet contenant une référence ne devrait pas être assignable, car une référence ne devrait pas être changée une fois initialisée?
Évitez les membres de référence, car ils limitent ce que l'implémentation d'une classe peut faire (y compris, comme vous le dites, empêcher l'implémentation d'un opérateur d'affectation) et n'apportent aucun avantage à ce que la classe peut fournir.
Exemple de problèmes:
.
, etc.), mais se comporte comme un pointeur (peut être suspendue) - par ex. Google Style Guide le décourageMa propre règle de base:
Les objets devraient rarement permettre d’assigner des tâches et d’autres choses comme la comparaison. Si vous envisagez un modèle d'entreprise avec des objets tels que «Département», «Employé», «Directeur», il est difficile d'imaginer un cas où un employé sera affecté à un autre.
Pour les objets métier, il est donc très utile de décrire les relations un à un et un à plusieurs comme des références et non des pointeurs.
Et il est probablement correct de décrire la relation un ou zéro comme un pointeur.
Donc, non, nous ne pouvons pas affecter ce facteur.
Beaucoup de programmeurs s'habituent simplement aux pointeurs et c'est pourquoi ils trouveront n'importe quel argument pour éviter l'utilisation de la référence.
Avoir un pointeur en tant que membre vous obligera, vous ou un membre de votre équipe, à vérifier le pointeur encore et encore avant utilisation, avec un commentaire "juste au cas où". Si un pointeur peut être égal à zéro, le pointeur est probablement utilisé comme une sorte d’indicateur, ce qui est mauvais, car chaque objet doit jouer son propre rôle.
Dans quelques cas importants, l’assignabilité n’est tout simplement pas nécessaire. Ce sont souvent des wrappers d'algorithmes légers qui facilitent les calculs sans quitter la portée. De tels objets sont les premiers candidats pour les membres de référence car vous pouvez être sûr qu'ils ont toujours une référence valide / et qu'ils n'ont jamais besoin d'être copiés.
Dans de tels cas, veillez à rendre l'opérateur d'affectation (et souvent aussi le constructeur de copie) non utilisable (en héritant de boost::noncopyable
ou en les déclarant privés).
Cependant, comme les utilisateurs pts ont déjà commenté, il n'en va pas de même pour la plupart des autres objets. Ici, utiliser des membres de référence peut être un problème énorme et devrait généralement être évité.
Comme tout le monde semble donner des règles générales, je vais en proposer deux:
Jamais, jamais utiliser des références d'utilisation en tant que membres de classe. Je ne l'ai jamais fait dans mon propre code (sauf pour me prouver que j'avais raison avec cette règle) et je ne peux pas imaginer un cas où je le ferais. La sémantique est trop déroutante et ce n’est vraiment pas la raison pour laquelle les références ont été conçues.
Toujours, toujours, utilisez des références lorsque vous passez des paramètres à des fonctions, sauf pour les types de base, ou lorsque l'algorithme nécessite une copie.
Ces règles sont simples et m'ont bien servi. Je laisse faire des règles sur l'utilisation de pointeurs intelligents (mais s'il vous plaît, pas auto_ptr) en tant que membres du groupe aux autres.
Oui à: Est-il vrai de dire qu'un objet contenant une référence ne doit pas être assignable, car une référence ne doit pas être modifiée une fois initialisée?
Mes règles empiriques pour les membres de données:
En règle générale, je n’utiliserais un pointeur dans les données de membre que si le pointeur pouvait être nul ou pouvait changer. Existe-t-il d'autres raisons de préférer les pointeurs aux références pour les membres de données?
Oui. Lisibilité de votre code. Un pointeur indique plus clairement que le membre est une référence (ironiquement :)) et non un objet contenu, car lorsque vous l'utilisez, vous devez le dé-référencer. Je sais que certaines personnes pensent que c'est démodé, mais je pense toujours que cela évite simplement la confusion et les erreurs.
Je déconseille aux membres des données de référence car vous ne savez jamais qui va dériver de votre classe et ce qu'ils voudront peut-être faire. Ils ne souhaitent peut-être pas utiliser l'objet référencé, mais en tant que référence, vous les avez obligés à fournir un objet valide . Je me suis suffisamment fait cela pour cesser d'utiliser des membres de données de référence.
Si je comprends bien la question ...
Référence en tant que paramètre de fonction au lieu de pointeur: Comme vous l'avez souligné, un pointeur n'indique pas clairement à qui appartient le nettoyage/l'initialisation du pointeur. Préférez un point partagé lorsque vous souhaitez un pointeur, il fait partie de C++ 11 et un faible_ptr lorsque la validité des données n'est pas garantie pendant toute la durée de vie de la classe acceptant les données pointées. également une partie de C++ 11 . L'utilisation d'une référence en tant que paramètre de fonction garantit que la référence n'est pas nulle. Il faut subvertir les fonctionnalités du langage pour résoudre ce problème, et nous ne nous soucions pas des codeurs de canons mal fixés.
Référence une variable a membre: Comme ci-dessus en ce qui concerne la validité des données. Cela garantit que les données pointées, puis référencées, sont valides.
Le fait de déplacer la responsabilité de validité variable vers un point antérieur du code nettoie non seulement le code suivant (la classe A dans votre exemple), mais le précise également à l’utilisateur.
Dans votre exemple, qui est un peu déroutant (j'essaierais vraiment de trouver une implémentation plus claire), le A utilisé par B est garanti pour la durée de vie du B, B étant un membre de A, une référence le renforce. et est (peut-être) plus clair.
Et juste au cas où (un capot peu probable car cela n’aurait aucun sens dans le contexte de vos codes), une autre alternative, utiliser un paramètre non référencé, non pointeur A, copierait A et rendrait le paradigme inutile - I vraiment ne pense pas que vous entendez cela comme une alternative.
En outre, cela garantit également que vous ne pouvez pas modifier les données référencées, où un pointeur peut être modifié. Un pointeur const ne fonctionnerait que si le pointeur référencé/data n'était pas modifiable.
Les pointeurs sont utiles s'il n'est pas garanti que le paramètre A pour B soit défini ou s'il peut être réaffecté. Et parfois, un pointeur faible est trop bavard pour la mise en œuvre, et bon nombre de personnes ne savent pas ce qu'est un faible, ou ne les aiment pas.
Découpez cette réponse, s'il vous plaît :)