J'apprends le C++ en ce moment et j'essaie d'éviter de prendre de mauvaises habitudes. D'après ce que j'ai compris, clang-tidy contient de nombreuses "meilleures pratiques" et j'essaie de m'y tenir le mieux possible (même si je ne comprends pas forcément pourquoi ils sont déjà considérés comme bons), mais je ne suis pas sûr de comprendre ce qui est recommandé ici.
J'ai utilisé cette classe du tutoriel :
class Creature
{
private:
std::string m_name;
public:
Creature(const std::string &name)
: m_name{name}
{
}
};
C'est pourquoi clang-tidy m'a suggéré de passer par une valeur au lieu d'une référence et d'utiliser std::move
. Si c'est le cas, on me propose de faire name
une référence (pour s'assurer qu'il n'est pas copié à chaque fois) et l'avertissement suivant std::move
n'aura aucun effet car name
est un const
Je devrais donc le supprimer.
La seule façon de ne pas recevoir d'avertissement est de supprimer const
tout à fait :
Creature(std::string name)
: m_name{std::move(name)}
{
}
Ce qui semble logique, puisque le seul avantage de const
était d'éviter d'altérer la chaîne de caractères originale (ce qui n'est pas le cas puisque je suis passé par valeur). Mais j'ai lu CPlusPlus.com :
Notez toutefois que, dans la bibliothèque standard, le déplacement implique que l'objet déplacé est laissé dans un état valide mais non spécifié. Cela signifie qu'après une telle opération, la valeur de l'objet déplacé ne doit être détruite ou affectée d'une nouvelle valeur que si l'on y accède autrement, on obtient une valeur non spécifiée.
Imaginez maintenant ce code :
std::string nameString("Alex");
Creature c(nameString);
Parce que nameString
est transmis par sa valeur, std::move
n'invalidera que les name
dans le constructeur et ne pas toucher à la chaîne de caractères originale. Mais quels sont les avantages de cette solution ? Il semble que le contenu ne soit copié qu'une seule fois de toute façon - si je passe par référence quand j'appelle m_name{name}
Si je passe par la valeur lorsque je la passe (et qu'elle est ensuite déplacée). Je comprends que c'est mieux que de passer par valeur et de ne pas utiliser std::move
(parce qu'il est copié deux fois).
Deux questions donc :
- Ai-je bien compris ce qui se passe ici ?
- Y a-t-il un avantage à utiliser
std::move
plutôt que de passer par référence et d'appeler simplementm_name{name}
?
7 votes
Avec passage par référence,
Creature c("John");
fait une copie supplémentaire2 votes
Ce lien pourrait être une lecture intéressante, il couvre le passage
std::string_view
et SSO.5 votes
J'ai trouvé
clang-tidy
est un excellent moyen de m'obséder avec des micro-optimisations inutiles au détriment de la lisibilité. La question qu'il faut se poser ici, avant toute autre chose, est de savoir combien de fois nous en fait appeler leCreature
constructeur.