Au lieu de ce code "non standard" :
#import <string>
#import <iostream>
void example(const std::string& x) {
size_t length = x.length();
for (size_t i = 0; i < length; ++i) {
std::cout << x.at(i) << std::endl;
}
}
int main() {
example("hello");
}
j'écrirais ça :
#include <string>
#include <iostream>
using namespace std;
void example( string const& s )
{
for( char const ch : s )
{
cout << ch << '\n';
}
}
auto main()
-> int
{ example( "hello" ); }
Le principal endroit où je pourrais ajouter const
par rapport au code d'origine, était pour les ch
dans la boucle. Je pense que c'est bien. const
est généralement souhaitable parce qu'elle réduit le nombre d'actions de code possibles à prendre en compte, et les boucles basées sur l'intervalle vous permettent d'avoir plus d'actions de code. const
.
Le principal inconvénient de l'utilisation const
pour la plupart des choses, c'est lorsque vous devez vous rapporter aux API C.
Il ne reste plus qu'à prendre des décisions à l'instinct pour savoir s'il faut copier les données, ou faire confiance à la documentation et utiliser un logiciel de gestion des données. const_cast
.
Addendum 1 :
Notez bien que const
sur un type de retour empêche la sémantique du déplacement. Pour autant que je sache, cela a été noté pour la première fois par Andrei Alexandrescu dans son article intitulé Article Mojo (sémantique des mouvements C++03) dans le Journal du Dr Dobbs :
" [A] const
temporaire ressemble à un oxymoron, une contradiction dans les termes. D'un point de vue pratique, const
les temporaires forcent la copie à la destination.
Donc, c'est un endroit où l'on devrait no utiliser const
.
Désolé d'avoir oublié de mentionner ce point à l'origine ; j'ai été rappelé par Commentaire de l'utilisateur bogdan sur une autre réponse.
Addendum 2 :
Dans la même veine (pour supporter la sémantique du déplacement), si la dernière chose faite avec un argument formel est de stocker une copie quelque part, alors au lieu de passer par référence à const
il peut être préférable d'utiliser un non const
l'argument passé par valeur, car il peut être simplement déplacé de.
C'est-à-dire qu'au lieu de
string stored_value;
void foo( string const& s )
{
some_action( s );
stored_value = s;
}
ou la redondance de l'optimisé
string stored_value;
void foo( string const& s )
{
some_action( s );
stored_value = s;
}
void foo( string&& s )
{
some_action( s );
stored_value = move( s );
}
envisager d'écrire simplement
string stored_value;
void foo( string s )
{
some_action( s );
stored_value = move( s );
}
Elle peut être légèrement moins efficace dans le cas d'un argument réel de valeur l, mais elle perd les avantages de const
(contraintes sur ce que le code peut éventuellement faire), et il rompt une convention uniforme d'utilisation de l'option const
dans la mesure du possible, mais il ne donne pas de mauvais résultats dans toutes les situations (ce qui est le but principal, éviter cela) et c'est un code plus petit et peut-être plus clair.
Notes :
¹ Le standard C++ n'a pas d #import
directive. De plus, ces en-têtes, lorsqu'ils sont correctement inclus, ne sont pas garantis pour définir les directives size_t
dans l'espace de noms global.