Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

boucles for

8 réponses
Avatar
JBB
Voici un petite boucle classique ( qui est du c d'ailleurs)

for (int i =0; i < NombreIteration(); ++i) {...}

dans le mesure ou NombreIteration() va renvoyer toutjours la même valeur
je peux optimiser en:

const int nombreIteration = NombreIteration();
for (int i =0; i < nombreIteration; ++i) {...}

mon probleme est que du coup nombreIteration existe encore apres ma boucle, j'aimerais limiter sa
portée à ma boucle.

du coup je peux faire:
for (int i =0,nombreIteration = NombreIteration(); i < nombreIteration; ++i) {...}

Par contre du coup nombreIteration n'est plus const ce qui ne me plait pas beaucoup.

J'aimerais pouvoir faire:
for (int i = 0, const int nombreIteration = NombreIteration(); i < nombreIteration; ++i) {...}
Mais la ça ne compile plus...

Y a t'il une solution pour moi?

8 réponses

Avatar
JBB
Et j'ai oublié le principal:

Bonjour et Merci
Avatar
Fabien LE LEZ
On Tue, 07 Feb 2006 15:07:40 +0100, JBB :

const int nombreIteration = NombreIteration();
for (int i =0; i < nombreIteration; ++i) {...}

mon probleme est que du coup nombreIteration existe encore apres ma boucle, j'aimerais limiter sa
portée à ma boucle.


{
const int nombreIteration = NombreIteration();
for (int i =0; i < nombreIteration; ++i) {...}
}

Avatar
Vincent Jacques
On Tue, 07 Feb 2006 15:07:40 +0100, JBB :


const int nombreIteration = NombreIteration();
for (int i =0; i < nombreIteration; ++i) {...}

mon probleme est que du coup nombreIteration existe encore apres ma boucle, j'aimerais limiter sa
portée à ma boucle.



{
const int nombreIteration = NombreIteration();
for (int i =0; i < nombreIteration; ++i) {...}
}



Ou, si c'est possible de changer l'ordre,

for(int i = NombreIteration(); i > 0; --i) {}

On peut aussi imaginer ce qui suit, mais euh comment dire, je n'y ai pas
réfléchi, il est possible que ce soit une mauvaise idée :-)

class ControleurDeBoucle
{
public:
ControleurDeBoucle(int fin) : m_fin(fin),m_actuel;(0) {};
bool Continuer() {return m_actuel;<m_fin;};
void Avancer() {m_actuel;++);
int Actuel() {return m_actuel};
private:
const int m_fin;
int m_actuel;
};

for(ControleurDeBoucle c(NombreIteration()), c.Continuer(), c.Avancer())
{ ... }

--
Vincent Jacques

"S'il n'y a pas de solution, c'est qu'il n'y a pas de problème."
Devise Shadok


Avatar
Cyrille
On Tue, 07 Feb 2006 15:07:40 +0100, JBB :


const int nombreIteration = NombreIteration();
for (int i =0; i < nombreIteration; ++i) {...}

mon probleme est que du coup nombreIteration existe encore apres ma
boucle, j'aimerais limiter sa portée à ma boucle.



{
const int nombreIteration = NombreIteration();
for (int i =0; i < nombreIteration; ++i) {...}
}



Ou, si c'est possible de changer l'ordre,

for(int i = NombreIteration(); i > 0; --i) {}


Tu voulais sans doute écrire:
for(int i = NombreIteration()-1; i >= 0; --i) {}

Mais ce serait une mauvaise idée. La solution canonique est celle de
Fabien: les signes { } ont justement cette sémantique, entre autres, de
définir la portée des variable locales.
A contrario, l'incrémentation d'une variable de 0 à N est la manière la
plus naturelle de parcourir une boucle avec une variable. Quand je vois
une boucle parcourue dans ce sens "inverse", je me dis qu'il doit y
avoir une raison, qui tient à l'algorithme contenu dans la boucle. Si
cette inversion n'est là que pour éviter d'avoir une variable locale qui
traîne dans la portée, ça ne sert qu'à obfusquer le code.

Quand on veut faire quelque chose, il vaut mieux utiliser ce que le
langage offre et qui répond directement à ça plutôt qu'une "astuce".

On peut aussi imaginer ce qui suit, mais euh comment dire, je n'y ai pas
réfléchi, il est possible que ce soit une mauvaise idée :-)

class ControleurDeBoucle
{
public:
ControleurDeBoucle(int fin) : m_fin(fin),m_actuel;(0) {};
bool Continuer() {return m_actuel;<m_fin;};
void Avancer() {m_actuel;++);
int Actuel() {return m_actuel};
private:
const int m_fin;
int m_actuel;
};

for(ControleurDeBoucle c(NombreIteration()), c.Continuer(), c.Avancer())
{ ... }


En fait si ça ça compile, je serais très surpris.



Avatar
Fabien LE LEZ
On Tue, 07 Feb 2006 21:18:22 +0100, Cyrille :

La solution canonique est celle de
Fabien: les signes { } ont justement cette sémantique, entre autres, de
définir la portée des variable locales.


Yep.
On retrouve ce même idiome dans un cas où la durée de vie d'une
variable est particulièrement importante : le RAII.

Avatar
Vincent Jacques
Tu voulais sans doute écrire:
for(int i = NombreIteration()-1; i >= 0; --i) {}

Mais ce serait une mauvaise idée.
Quand on veut faire quelque chose, il vaut mieux utiliser ce que le
langage offre et qui répond directement à ça plutôt qu'une "astuce".


Oui, ya pas de doute.

On peut aussi imaginer ce qui suit, mais euh comment dire, je n'y ai
pas réfléchi, il est possible que ce soit une mauvaise idée :-)

[n'importe quoi... j'avais pas le clavier en face des doigts]


En fait si ça ça compile, je serais très surpris.


:-) Et quant à l'idée elle-même, vous en pensez quoi? C'est un peu sortir
le marteau-pilon pour écraser une mouche, mais j'aimerais des avis
extérieurs.

Des fois que cette idée aurait été trop masquée par mes erreurs de
frappe, voici ce que je voulais dire:

#include <iostream>

class ControleurDeBoucle
{
private:
const int m_fin;
int m_actuel;
public:
ControleurDeBoucle(int fin) : m_fin(fin),m_actuel(0) {};
bool Continuer() {return m_actuel<m_fin;};
void Avancer() {m_actuel++;};
int Actuel() {return m_actuel;};
};

int NombreIterations()
{
return 5;
}

int main()
{
for(ControleurDeBoucle c(NombreIterations());
c.Continuer();
c.Avancer())
{
std::cout << "coucou n°" << c.Actuel() << std::endl;
}
}

--
Vincent Jacques

"S'il n'y a pas de solution, c'est qu'il n'y a pas de problème."
Devise Shadok


Avatar
kanze
Cyrille wrote:
On Tue, 07 Feb 2006 15:07:40 +0100, JBB :

const int nombreIteration = NombreIteration();
for (int i =0; i < nombreIteration; ++i) {...}

mon probleme est que du coup nombreIteration existe encore apres ma
boucle, j'aimerais limiter sa portée à ma boucle.


{
const int nombreIteration = NombreIteration();
for (int i =0; i < nombreIteration; ++i) {...}
}


Ou, si c'est possible de changer l'ordre,

for(int i = NombreIteration(); i > 0; --i) {}


Tu voulais sans doute écrire:
for(int i = NombreIteration()-1; i >= 0; --i) {}


Ou plutôt :

for ( int count = NombreIteration() ; count > 0 ; -- count ) ...

(Qui a l'avantage de fonctionner même si pour une raison
quelconque on est amené à utiliser un type non-signé. Ce que je
déconseille, mais rien n'empèche de porter des bretelles et une
ceinture.)

Mais ce serait une mauvaise idée. La solution canonique est
celle de Fabien: les signes { } ont justement cette
sémantique, entre autres, de définir la portée des variable
locales.


La solution « canonique », depuis au moins « Structured
Programming », de Dijkstra, Hoare et Dahl, c'est de mettre la
boucle dans une fonction à part. Et de ne pas s'occuper de la
durée de vie des variables autrement.

C'est aussi ce que nous enseigne la STL.

A contrario, l'incrémentation d'une variable de 0 à N est la
manière la plus naturelle de parcourir une boucle avec une
variable. Quand je vois une boucle parcourue dans ce sens
"inverse", je me dis qu'il doit y avoir une raison, qui tient
à l'algorithme contenu dans la boucle.


La raison, souvent, c'est qu'on ne s'intéresse pas de la valeur
de l'indice dans la boucle, et que c'est la façon la plus
naturelle à implémenter « n fois ».

Si cette inversion n'est là que pour éviter d'avoir une
variable locale qui traîne dans la portée, ça ne sert qu'à
obfusquer le code.


Rien à faire. L'inversion, c'est là parce que la seule
« invariante », c'est qu'il nous reste i fois à parcourir la
boucle.

for ( int i = 0 ; i < N ; ++ i ) ...
c'est indicatif que la valeur d'i a une signification ; qu'on
l'utilise comme indice. (Sinon, d'ailleurs, il ne s'appellera
pas « i »:-). Les noms aussi courts sont à éviter, mais « i »
est le nom consacré d'une indice.)

Quand on veut faire quelque chose, il vaut mieux utiliser ce
que le langage offre et qui répond directement à ça plutôt
qu'une "astuce".

On peut aussi imaginer ce qui suit, mais euh comment dire,
je n'y ai pas réfléchi, il est possible que ce soit une
mauvaise idée :-)

class ControleurDeBoucle
{
public:
ControleurDeBoucle(int fin) : m_fin(fin),m_actuel;(0) {};
bool Continuer() {return m_actuel;<m_fin;};
void Avancer() {m_actuel;++);
int Actuel() {return m_actuel};
private:
const int m_fin;
int m_actuel;
};

for(ControleurDeBoucle c(NombreIteration()), c.Continuer(), c.Avancer())
{ ... }


En fait si ça ça compile, je serais très surpris.


En dehors des fautes de frappe ? Il y a plusieurs fautes de
frappe évidentes, mais je ne vois pas de problème en principe.

À part, évidemment, que c'est très lourd, et qu'il masque un
opération très simple.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34




Avatar
Fabien LE LEZ
On Tue, 07 Feb 2006 21:59:38 +0100, Vincent Jacques
:

Et quant à l'idée elle-même, vous en pensez quoi? C'est un peu sortir
le marteau-pilon pour écraser une mouche, mais j'aimerais des avis
extérieurs.


Ben... généralement, quand on sort le marteau-pilon pour écraser une
mouche, c'est pour éviter d'utiliser for -- i.e. le remplacer par
for_each, avec 50 lignes de codes pour que ça marche. (Cf certains
messages de James.)