Évaluation de la condition en boucles?
-
19-08-2019 - |
Question
string strLine;//not constant
int index = 0;
while(index < strLine.length()){//strLine is not modified};
combien de fois strLine.length()
sont évalués
devons-nous mettre l'utilisation nLength
avec <=> attribué à <=> juste avant la boucle
La solution
length
sera évalué chaque fois que vous passerez dans la boucle. Toutefois, étant donné que O(1)
est un temps constant (<=>), cela ne fait pas grande différence et l'ajout d'une variable pour stocker cette valeur aura probablement un effet négligeable. effet avec un petit impact sur la lisibilité du code (ainsi que de casser le code si la chaîne est modifiée).
Autres conseils
length () est défini dans les en-têtes inclus dans votre fichier source. Il peut donc être inséré en ligne par le compilateur. Ses appels internes peuvent également être insérés en ligne. Par conséquent, si le compilateur peut détecter que votre instance de chaîne n'est pas modifiée dans la boucle, il peut alors optimiser l'accès à la longueur d'une chaîne, de sorte qu'elle ne sera évaluée qu'une seule fois. Dans tous les cas, je ne pense pas que stocker la valeur de la longueur de la chaîne soit vraiment nécessaire. Peut-être que cela peut vous faire économiser des nanosecs, mais votre code sera plus gros et il y aura un risque lorsque vous déciderez de changer cette chaîne dans la boucle.
Chaque fois, il est appelé ... (chaque évaluation). Si vous ne changez pas la longueur de la chaîne, il vaut mieux utiliser une variable temporaire telle que:
string strLine;
int stringLength = strLine.length();
int index = 0;
while(index < stringLength);
Je pense qu'il y a une deuxième question qui se cache à l'intérieur de cela, et c'est & "quelle implémentation est plus claire? &";
Si, sémantiquement, vous voulez que la longueur de strLine ne change jamais dans le corps de la boucle, rendez-la évidente en attribuant une variable bien nommée. Je ferais même le const. Cela montre clairement aux autres programmeurs (et à vous-même) que la valeur de comparaison ne change jamais.
L’autre chose que cela permet de voir plus facilement quelle est cette valeur lorsque vous parcourez le code dans un débogueur. Le survol fonctionne mieux sur un local que sur un appel de fonction.
Dire, & "Laissons-le comme un appel de fonction; le compilateur l'optimisera " me semble une pessimisation prématurée. Même si length () est O (1), s'il n'est pas aligné (vous ne pouvez pas garantir que les optimisations ne sont pas désactivées), il s'agit toujours d'un appel de fonction non trivial. En utilisant une variable locale, vous clarifiez votre signification et vous obtenez une optimisation des performances éventuellement non triviale.
Faites ce qui rend votre intention plus claire.
strLine.length () sera évalué alors que (i < strLine.length ())
Cela dit, si la chaîne est constante, la plupart des compilateurs l'optimiseront (avec les paramètres appropriés).
Si vous allez utiliser une variable temporelle, utilisez un qualificatif const afin que le compilateur puisse ajouter des optimisations tout en sachant que la valeur ne changera pas:
string strLine;//not constant
int index = 0;
const int strLenght = strLine.Length();
while(index < strLine.length()){//strLine is not modified};
De toute façon, le compilateur lui-même effectue ces optimisations lorsqu’il accède quand même à la méthode Length ().
Edit: mon montage est un peu rouillé, mais je pense que l'évaluation n'a lieu qu'une fois. Étant donné ce code:
int main()
{
std::string strLine="hello world";
for (int i=0; i < strLine.length(); ++i)
{
std::cout << strLine[i] <<std::endl;
}
}
Génère cet assemblage:
for (int i=0; i < strLine.length(); ++i)
0040104A cmp dword ptr [esp+20h],esi
0040104E jbe main+86h (401086h)
Mais pour ce code
std::string strLine="hello world";
const int strLength = strLine.length();
for (int i=0; i < strLength ; ++i)
{
std::cout << strLine[i] <<std::endl;
}
génère celui-ci:
for (int i=0; i < strLength ; ++i)
0040104F cmp edi,esi
00401051 jle main+87h (401087h)
Le même assemblage est généré si un qualificatif const n'est pas utilisé. Dans ce cas, cela ne fait aucune différence.
Essayé avec VSC ++ 2005
Comme indiqué, étant donné que la fonction string::length
est probablement entièrement définie dans un en-tête et doit obligatoirement être O (1), il est presque certain de l'évaluer comme un simple accès membre et de s'inscrire dans votre code. Puisque vous ne déclarez pas la chaîne comme étant volatile, le compilateur est autorisé à imaginer qu’aucun code extérieur ne la modifiera, à optimiser l’appel sur un accès mémoire unique et à laisser la valeur dans un registre s’il découvre que c’est un bonne idée.
En récupérant vous-même et en mettant en cache la valeur, vous augmentez les chances que le compilateur puisse faire la même chose. Dans de nombreux cas, le compilateur ne générera même pas le code pour écrire la longueur de chaîne dans la pile et le laissera simplement dans un registre. Bien sûr, si vous appelez différentes fonctions que le compilateur ne peut pas insérer en ligne, la valeur devra alors être écrite dans la pile pour empêcher les appels de fonction de perturber le registre.
Puisque vous ne changez pas la chaîne, ne devriez-vous pas utiliser
const string strLine;
Simplement, car le compilateur obtient alors plus d'informations sur ce qui peut et ne peut pas changer - vous ne savez pas exactement à quel point un compilateur C ++ peut être intelligent, cependant.
strLine.length()
sera évalué chaque fois que vous contournez la boucle.
Vous avez raison de dire qu'il serait plus efficace d'utiliser nLength
, surtout si strLine
est long.