pointeurs non facultatifs vs références non const en C ++

12

Dans Other C ++ Features, Reference Arguments of the Google C ++ Style Guide , j'ai lu que les références non const ne doivent pas être utilisées.

Tous les paramètres passés par référence doivent être étiquetés const.

Il est clair que regarder les appels de fonction qui utilisent des références comme arguments est absolument déroutant pour les programmeurs C, mais C et C ++ sont maintenant des langages différents. Si un paramètre de sortie est requis , l'utilisation d'un pointeur pour un paramètre de sortie requis peut entraîner le saut de tout le corps de la fonction, ce qui complique la mise en œuvre d'une fonction (augmente formellement la complexité cyclonique et la profondeur d'une fonction).

J'aimerais rendre le code C ++ aussi facile à comprendre / à gérer que possible, donc je suis généralement intéressé par la lecture des guides de style de codage. Mais pour adapter les meilleures pratiques au sein d'une équipe, je pense que la compréhension de la logique des éléments du guide de style est un facteur important.

Les références non const sont-elles vraiment si mauvaises? Leur interdiction est-elle uniquement spécifique à Google ou est-ce une règle communément acceptée? Qu'est-ce qui justifie l'effort supplémentaire pour implémenter les paramètres de sortie en tant que pointeurs?

Loup
la source
2
"utiliser un pointeur pour cela fait sauter le corps de la fonction entière" euh, quoi?
ratchet freak
@ratchetfreak J'ai essayé de clarifier cela. J'admets que des fonctions comme celle-ci peuvent présenter des défauts de conception. Un pointeur est toujours formellement facultatif, il doit donc être vérifié avant de le déréférencer.
Wolf
4
Le guide de style C ++ de Google est assez en arrière. À mon avis subjectif, il devrait être brûlé.
Siyuan Ren
En ce qui concerne cet élément particulier, je pense que la justification est que forcer les programmeurs à écrire une esperluette lorsque les arguments peuvent être mutés montre une intention plus claire.
Siyuan Ren
4
Le Google Style Guide a été rédigé tel quel pour prendre en charge un code homogène dans les projets hérités de Google. Si vous ne travaillez pas sur des projets hérités (qui ont été écrits avec ce guide de style depuis le début), vous ne devriez probablement pas l'utiliser (il spécifie de nombreuses règles qui ne conviennent pas au nouveau code (c ++ 11, c ++ 14 , c ++ 17)).
utnapistim

Réponses:

18

La raison d'être du guide de style de Google est simplement d'indiquer clairement à partir du site d'appel d'une fonction si un paramètre est un paramètre d'entrée ou un paramètre de sortie. (Voir ici pour plus de détails.) D'autres langages établissent les paramètres de manière explicite par conception; C #, par exemple, a un outmot-clé qui doit être utilisé sur le site d'appel . Puisque C ++ ne le rend pas explicite, Google a choisi d'utiliser const ref. versus pointeur pour le rendre clair.

S'agit-il uniquement d'une règle Google? Non, mais je doute que ce soit très répandu. Je ne pense pas l'avoir vu en dehors du guide de style de Google et des groupes qui adhèrent explicitement à certaines parties du guide de style de Google. (Par exemple, j'ai aimé l'idée lorsque j'ai lu le guide de style Google pour la première fois il y a des années et je l'ai utilisé pour une partie de mon propre code.)

En particulier, les directives C ++ Core nouvellement annoncées préfèrent les valeurs de retour aux paramètres de sortie pour (presque) tout et utilisent des références non const pour le reste. L'utilisation par Google des pointeurs par rapport aux références peut rendre les paramètres de sortie plus clairs, mais les valeurs de retour sont toujours plus claires. Maintenant que C ++ 11 a des mouvements standardisés (références rvalue &&, pour rendre les retours de nombreux types bon marché) et des tuples (permettant un moyen facile de renvoyer plusieurs valeurs), de nombreux cas d'utilisation des paramètres out ne s'appliquent plus.

Les directives de base C ++ ont de grands noms (Bjarne Stroustrup, Herb Sutter), sont prises en charge par Microsoft et incluent les dernières fonctionnalités C ++ (contrairement au guide de style de Google), donc je m'attends à ce que ses recommandations soient plus populaires que celles de Google.

Josh Kelley
la source
Merci pour votre réponse (également pour la brève excursion en C #). Un examen facile est bien sûr un point important, en particulier dans les projets Open Source. Avec des retours bon marché dans le C ++ moderne, ces considérations perdront de leur importance. Avec les anciens logiciels hérités et les anciens compilateurs, cela peut toujours être utile.
Wolf
Je ne l'ai pas oublié, mais les directives de base C ++ ne sont pas aussi rapides à obtenir. Il est intéressant de noter que sa philosophie montre la raison d'être des règles et également une vision modernisée de la programmation ("Exprimer des idées directement dans le code" se lit un peu comme le Zen de python) comme moyen de communiquer.
Wolf
Supplément: lien direct vers la section Philosophie des directives du code C ++.
Wolf
1

Il existe 2 options pour gérer un pointeur invalide transmis, une première vérification et un retour anticipé ou qu'il s'agisse d'un comportement non défini (si vous vous souciez plus de la vitesse que de la robustesse).

La vérification est aussi simple que:

void foo(void* buffer){
    if(buffer == nullptr)
        return;

    //actually foo

    // note no increase in indentation required

}

Ce type de vérification est généralement accepté comme vérification des paramètres. Si vous voyez le code, il est clair que vous vous attendez à ce qu'un pointeur non nul soit transmis et revienne tôt sinon. Cela vous permet de ne pas trop vous soucier des pointeurs invalides.

monstre à cliquet
la source
Eh bien, j'ai pensé à ce modèle et le trouve absolument raisonnable. Malheureusement, il ne semble pas aussi clair que assert(buffer);sachant que l'assertion n'est active que pour la version de débogage, je souhaite parfois avoir un rt_assert(buffer);qui lève une exception. L'indentation des returnregards un peu dangereux ... BTW: votre extrait de code est une bonne illustration de ma question sur les pointeurs de sortie.
Wolf
1

Cela revient à votre observation If an output parameter is required.

Le seul endroit où une signature de fonction est requise pour avoir un paramètre de sortie est lorsqu'il est spécifié par une API externe, et dans un tel cas, vous enveloppez simplement l'API externe dans quelque chose qui garantit qu'il y a toujours une pointe valide.

En interne, vous évitez les paramètres de sortie en étendant le type de retour pour qu'il soit un composite de toutes les "sorties"

Caleth
la source
Vous voulez dire, le seul endroit où je ne suis pas en mesure de fournir un pointeur non obligatoire? C'est vrai, mais je ne sais pas si votre règle The only place where...est vraiment applicable à tous les cas. Voici ce que vous proposez: évitez les paramètres de sortie dans les fonctions de vos propres programmes. Vrai pour les nouveaux programmes.
Wolf
1
Oui, évitez les paramètres de sortie, préférez les types de retour composites, édités pour que ce soit plus clair
Caleth