Quelle est la meilleure façon de rétablir la chaîne en C++?
Ma question est simple: si j'ai un peu de classe Homme et je veux définir une fonction membre qui renvoie nom de l'homme, lequel de ces deux variantes est que je préfère?
Première:
string name();
Deuxième:
void name(/* OUT */ string &name);
La première variante est une sorte de inefficace, car elle rend inutiles les copies (variable locale -> valeur de retour -> variable dans la partie gauche de l'affectation).
La deuxième variante à l'air assez efficace, mais il me fait pleurer à écrire
string name;
john.name(name);
au lieu d'une simple
string name(john.name());
Alors, quelle variante est que je préfère et ce qui est le bon compromis entre l'efficacité et la commodité et la lisibilité?
Merci d'avance.
- Note de côté, comme
name()
ressemble à une requête en faireconst
:string name() const;
. - Pourquoi le premier
const
? L'objet retourné finit appartenant au client, et il devrait être libre de faire ce qu'il veut. - qui ne fait pas partie de la signature, mais plutôt mon commentaire, c'est follwed par un":".
- Si c'est juste un simple de lecture de l'accès à un membre correspondant de la variable, un
const std::string&
pourrait même être une bonne idée. - Désolé, ensuite. Dans la police, je suis à l'aide, l' : ne fonctionne pas très bien à tous.
- Pas habituellement. Elle introduit des questions de durée de vie de la référence, etc. Dans une classe de base, il peut créer de réels problèmes pour la classe dérivée. Sauf si vous voulez réellement à l'appui de code client en se référant à des données internes (et sont prêts à documenter la validité de telles références), il est préférable d'éviter de retourner une référence. (Si la documentation de la fonction ne pas spécifier la durée de vie de la référence, alors je considère le code cassé.)
- L'une des nombreuses questions sur la RVO: stackoverflow.com/questions/7596183/...
- Remarque gentille, j'ai l'habitude de le faire. Merci 🙂
- Laisser
fullname()
fonction qui colle prénom et nom de l'ensemble et retourne le résultat.
Vous devez vous connecter pour publier un commentaire.
C'est une bonne question et le fait que vous demandez cela montre que vous êtes en accordant une attention à votre code. Cependant, la bonne nouvelle, c'est que dans ce cas particulier, il y a un moyen de sortir.
La première, propre méthode est la bonne façon de faire. Le compilateur va supprimer les copies, dans la plupart des cas (généralement où il fait sens).
MODIFIER (6/25/2016)
Malheureusement, il semble que David Abaraham du site a été hors ligne pendant quelques années maintenant et que l'article a été perdu à l'éther (pas de archive.org copie disponible). J'ai pris la liberté de transfert de ma copie locale de fichier PDF pour l'archivage, et il peuvent être trouvés ici.
utiliser la première variante:
Le compilateur le plus susceptible d'optimiser toutes les recopies inutiles. Voir valeur de retour d'optimisation.
En C++11, la sémantique de déplacement signifie que vous n'avez pas à effectuer une copie complète, même si le compilateur n'effectue pas de RVO. Voir la sémantique de déplacement.
Également de garder à l'esprit que si l'alternative est
il vous faudra alors préciser très clairement ce qui peut arriver à
s
et des valeurs qu'elle peut avoir lorsqu'il est passé à la fonction, et probablement faire beaucoup de vérification de la validité, ou tout simplement écraser l'entrée entièrement.Puisque vous voulez créer un getter pour un champ de votre classe, vous devriez peut-être aller comme ça:
inline const std::string& name() const { return this->name; }
Puisque le nom est retourné comme une référence const, il ne sera pas modifié en dehors de la classe, aussi aucune copie ne sera créé en retournant le nom.
Après, si vous voulez manipuler le nom que vous aurez à faire une copie.
setName
ousetFirstName
méthodes) et de le stocker dans un champ nom complet. De cette façon, vous n'aurez pas à recalculer les nom et prénom à chaque fois que vous appelezfullname()
, il vous suffit de le retourner const de référence pour le champ nom complet (comme écrit dans ma réponse).Je voudrais aller avec le premier. Valeur de retour d'optimisation et de C++11 va supprimer toute copie de frais généraux.
Comme nous l'avons déplacez-sémantique (en C++11), vous pouvez utiliser ceci:
Même en C++03, c'est presque bon, comme le compilateur peut optimiser ce (de Recherche pour la Valeur de Retour d'Optimisation).
Règle n ° 1 de l'optimisation: Mesure, d'optimiser, de mesure. Ou, comme Knuth a dit, "l'optimisation prématurée est la racine de tout mal".
Sauf si vous avez une forte indication que le fait de retourner simplement
std::string
auront un impact significatif sur la performance de votre logiciel, juste le faire. Si vous pouvez mesure un impact significatif, trouver le chemin critique, et d'optimiser que. Ne pas faire tout drôle, à l'échelle du projet "optimisation" qui résultent probablement de peu ou pas de gain de performances, mais un impact négatif sur la lisibilité, de la maintenabilité et la fiabilité de votre code.Je pense que vous devriez utiliser la première variante. Parce que c'est simple méthode de lecture et de telles getter/setter approche est utilisée partout.