[C++] conteneurs ordonnés

Résolu/Fermé
Bob - 4 janv. 2008 à 18:19
mamiemando Messages postés 33266 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 16 septembre 2024 - 7 janv. 2008 à 10:09
Bonjour,

J'ai un petit pb. J'aimerai utiliser la methode send(string nomExpediteur,string nom, int cout) pour signaler a tous mes voisins que l'expediteur peut atteindre nom avec cout saut (=distance).
Pour ça, j'aimerai pouvoir manipuler les tableRoutage des voisins. Verifier que nom se trouve ou pas dans la tableRoutage des voisins entre autre.
Avec des iterateurs, je vois très bien comment travailler sur chaque voisin. Mais je ne vois pas bien comment travailler sur les tables de routage de ces voisins.
Est-ce possible?

using namespace std;

class Hote{
   string nom;
   //variable incrementee a chaque creation d'un hote
   static int infini;
   map<string,Hote*> listeVoisins;
   map<string,pair<Hote*,int> > tableRoutage;

public:
   

   Hote(string n){
      infini++;
      nom=n;
      tableRoutage.insert(make_pair(n,make_pair(this,0)));
   }
   ~Hote(){
      infini--;
   }

   string getNom();
   void send(string nomExpediteur,string nom, int cout);
}


Merci pour votre aide!

5 réponses

mamiemando Messages postés 33266 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 16 septembre 2024 7 777
5 janv. 2008 à 03:36
Les const

Effectivement c'est mieux de les mettre. Tant que tu n'en utilises pas (ainsi que les gens qui codent avec toi) ce n'est pas gênant. Par contre le jour où quelqu'un manipule un objet devant être maintenu constant il ne pourra pas utiliser tes fonctions : en effet le "const" dans un prototype d'une fonction ou d'une méthode permet de dire que celle-ci ne va pas la modifier.

Dès lors ces paramètres peuvent être const ou non, ça marchera. Par contre le jour où tu voudras passer un paramètre const alors que dans le prototype, ledit paramètre n'est pas const, le compilateur va déclencher une erreur. En effet cette fonction ne garantira pas que le paramètre restera constant au cours de l'appel de cette fonction. Ainsi, mettre des const dans les prototypes quand c'est possible permet de généraliser le domaine d'application de tes fonctions. Un exemple :
void f1(int & x){
  ++x; // ok
}

void g1(const int & x){
  ++x; // pas ok car on modifie une variable constante
}

void h1(const int & x){
  std::cout << x << std::endl; // ok car  a pour prototype : std::ostream & operator << (std::ostream &,const int &)
}

int main(){
  const int x = 6;
  int y = 9;
  f1(x); // ok
  h1(x); // ok
  f1(y); // pas ok car f1 ne garantit pas la constance de y
  h1(y); // ok
  return 0;
}


Pour les classes

this (le pointeur sur l'instance auquel est appliqué la méthode) est un paramètre à part entière, et donc il est possible de préciser avec un const de dire si une méthode modifie ou non l'instance à laquelle elle s'applique.
class plop_t{
  protected:
  int x;  
  public:
  plop_t(const int & x0):x(x0){}

  void f() const {
    // je ne peux plus modifier les attributs de *this (ici x)
    // en contrepartie je peux appliquer la méthode f à un "const plop_t" 
  }

  void g(){
    // je peux modifier les attributs de *this
    // en contrepartie je ne peux pas appliquer la méthode g à un "const plop_t" 
  }
};

Attention

Dans un type la position d'un const est importante. Ainsi
const plop_t * p (ou plop_t const * p)
const plop_t * const p
plop_t * const p
plop_t *p

correspondent à quatre types de pointeur différents (idem avec les références). Une const placé devant l'étoile indique que l'objet pointé est maintenu constant. Un const placé derrière l'étoile signifie que l'adresse (le pointeur) est maintenu constant (mais pas ce qui est pointé)

Les const_iterator

Tu es obligé d'utiliser un const_iterator (ou const_reverse_iterator) pour itérer sur un container constant (par exemple un const std::set<int>), car les iterators classiques permettent de modifier le contenu d'un container (contrairement au const_iterator qui ne permettent qu'une lecture du contenu). Bien entendu, sur un container non const, tu peux utiliser les iterator ou les const_iterator selon tes besoins

Les références

Pour bien comprendre l'intérêt des références et des pointeurs il faut que tu gardes à l'esprit qu'en C et en C++, tout paramètre de fonction est recopié lors de l'appel de cette fonction. Si ce n'est pas clair pour toi il faut me le dire, ou que tu regardes un cours de C car c'est vraiment fondamental pour comprendre correctement ce langage.

Les références présentent l'avantage syntaxique de manipuler un objet passé en référence comme si on passait directement cet objet en paramètre. C'est donc beaucoup plus léger qu'un pointeur (plus besoin d'étoile et autre flèches !)

D'un point de vue fonctionnel par contre, tout se passe comme si on passait un pointeur sur cet objet (sauf que contrairement à un pointeur, une référence doit toujours être initialisée). Du coup on bénéficie des avantages des pointeurs :
- on peut modifier un paramètre passé en référence à une fonction. Par exemple ma fonction f1 va bien modifier la variable x au niveau du main, contrairement à cette fonction :
void f2(int x){
  ++x; // ok mais ce x est une recopie du x du main... ainsi cette incrémentation n'aura d'effet que dans f2
}

- on ne recopie pas le paramètre, on manipule juste son adresse. Ainsi si un objet est volumineux en mémoire et que j'ai besoin de le passer en paramètre d'une fonction, un passage par référence ou par pointeur sera beaucoup moins coûteux qu'une recopie.

Ca te va comme explication ? :-)
1
kilian Messages postés 8731 Date d'inscription vendredi 19 septembre 2003 Statut Modérateur Dernière intervention 20 août 2016 1 527
7 janv. 2008 à 00:41
Oooh, merci pour la leçon. Je savais pas que le const placé avant ou après l'étoile avait une signification différente.
0
mamiemando Messages postés 33266 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 16 septembre 2024 7 777
4 janv. 2008 à 21:21
Vue ta structure ça me parait possible : considérons un hote "u" et ses voisins "v1,v2....". Itérer sur le champ listeVoisins permet de parcourir les vi. Dès lors il est possible de les manipuler MAIS... le champ tableRoutage étant "protected", tu ne vas pas pouvoir le manipuler. Il faut donc soit mettre ce champ public, soit faire un accesseur sur tableRoutage, soit faire une méthode supplémentaire (par exemple maj_table_de_routage).

La troisième méthode étant la plus propre c'est celle qu'on va adopter :
void send(
//const std::string & nomExpediteur, // a priori c'est le champ nom de ton objet,
                                     // ce paramètre est donc inutile ?
  const std::string & nom_voisin,
  const unsigned & cout
) const {
  std::map<string,Hote*>::const_iterator mit(listeVoisins.find(nom_voisin));
  if (mit == listeVoisins.end()){
    std::cerr << nom << "n'a pas de voisin " << nom_voisin << std::endl;
    throw;
  }
  const Hote & hote_courant = mit->second;
  hote_courant.maj_table_de_routage(nom,this,cout);
}

inline void maj_table_de_routage(
  const std::string & nom_voisin,
  const Hote *hote_voisin,
  const unsigned & cout
){
  tableRoutage[nom] = std::make_pair(hote_voisin,cout);
}

Bien entendu je suppose que les métriques sont symétriques (ie |u,v| = |v,u| ?)

Bonne chance
0
Un GRAND merci, vraiment.
L'idee y est. Je vais adapter ça à mon code. Et ça devrait etre nickel.

Merci! et peut être à plus! :)

P.S: Je ne suis pas très doué en prog, et quand je compare ton code au mien, je vois que tu attaches bcp d'importance aux const, et au reference. Il y a aussi du const_iterator là ou moi je met du iterator tout court. Quand je met des const, ça a tendance à me générer des erreurs que je regle en les enlevant. Et le code marche sans ces const (à première vu en tout cas). Moralité : je fais du code pas très propre mais qui marche(mal?).
Si tu pouvais m'éclairer sur ces quelques points ça serait vraiment sympa.
0
Deux jours sans internet et votre post est perdu trois pages en arrière!

Un peu que ça me va comme explication! Merci de t'être donné cette peine, ça va m'aider pour la suite. Je vais faire mon possible en tout cas pour insérer des const dans mes codes les prochaines fois :-).

Allez au lit! Fini les vacances. Fallait bien que ça se termine ^^.

Et encore merci pour ton aide, je ne m'attendais pas à autant d'explication! C'est très sympa de ta part (En espérant que tu vois mon post malgré le retard)

A bientôt!
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
mamiemando Messages postés 33266 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 16 septembre 2024 7 777
7 janv. 2008 à 10:09
Pas de soucis, bonne continuation à tout les deux ;-)
0