2009-11-09 3 views
3

Je ne suis pas très bon en C++ mais je dois tester un système basé sur la réputation. Un fragment de code est donné ci-dessous ce qui me donne une erreur de segmentation quand je l'exécute sur le système d'ubuntu. Comme je l'ai écrit dans les commentaires, deux fonctions "tackleFirstHandInfo()" et "updateReputation()" s'exécutent correctement mais lorsque j'appelle une fonction de l'autre, elle plante. Toute aide sera grandement appréciée, merci d'avance. le code est ci-dessous:Erreur de segmentation dans la carte stl <>

"ex.h" 

#ifndef _ex_h 
#define _ex_h 
#include "iostream" 
#include <map> 
#define FADING 0.9 
enum Behaviour {FORWARDING, NOTFORWARDING}; 

class Rating 
{ 

private: 
    double reputation; 

public: 

    Rating() { reputation = 5.0; } 
    Rating(double rep) {reputation = rep;} 

    ~Rating() {} 

    double getRep() { return reputation; } 

    void updateRep(Behaviour behaviour) { 
     if (behaviour == FORWARDING) 
      reputation = reputation + 1;  
     else 
      reputation = reputation - 1;  
    } 

}; 

#endif 

"ex.cc" 

#include <map>         
#include <string> 
#include <iostream> 
#include "ex.h"       
using namespace std; 
typedef map<int, Rating*> ratingTable; 
class RepSys { 
private: 
    ratingTable repTable; 
    map<int, Rating*> fHandInfo; 
    Rating* rating; 

public: 
    RepSys(){} 
    ~RepSys(){} 

    void tackleFirstHandInfo(int address, Behaviour behaviour) 
    /* This Function and the function below individually run correctly */ 
    { 
     map<int, Rating*>::iterator it; 
     it=fHandInfo.find(address); 
     if (it == fHandInfo.end()) { 
      cout << "Adding New Entry for (fHandInfo) "<< address <<endl; 
      rating = new Rating(); 
      fHandInfo[address] = rating; 
     } 
     (it->second)->updateRep(behaviour); 
     cout<<"First Hand Reputation of "<<address<<"\t is ="<< (it->second)->getRep()<<endl; 
     updateReputation(address, behaviour); // This causes SegFault !!!! 
     return; 
    } 

    void updateReputation(int address, Behaviour behaviour) 
    { 
     map<int, Rating*>::iterator it; 
     it = repTable.find(address); 
     if (it == repTable.end()) { 
      cout << "Adding New Entry for (repTable) "<< address <<endl; 
      rating = new Rating(); 
      repTable[address] = rating; 
     } 
     (it->second)->updateRep(behaviour); 
     cout<<"Reputation of "<<address<<"\t is ="<< (it->second)->getRep()<<endl; 
    } 
}; 

int main() { 
    int address;  
    RepSys repsys; 
    while (address != 0) 
    {         
     cout << "Address\n"; 
     cin >> address; 
     repsys.tackleFirstHandInfo(address, FORWARDING); 
    } 
    return 0; 
} 
+0

Quelqu'un pourrait-il corriger le formatage? –

+0

veuillez prendre soin du formatage! – jldupont

+0

Là, c'est lisible maintenant. Même si je vois que les gens l'ont compris de toute façon. –

Répondre

10

L'un de vos principaux problèmes se produit dans les deux fonctions et est ceci:

if (it == fHandInfo.end()){ 
    // Some code that doesn't alter 'it' 
} 
(it->second)->updateRep(behaviour); 

Si it ne pointe à la fin il n'est pas dereferencable, de sorte que le it->second a comportement indéfini. Si vous voulez insérer quelque chose et que vous souhaitez que it pointe dessus, vous devez refaire le find ou utiliser une méthode d'insertion qui renvoie un itérateur (ou une paire incluant un itérateur) et ré-affecter it à la partie correcte de la valeur de retour .

Modifier

Quelques points:

class RepSys { 
private: 
    ratingTable repTable; 
    map<int, Rating*> fHandInfo; 
    Rating* rating; 

Vous avez déjà typedef ed ratingTable d'être map<int, Rating*>. Il semble un peu incohérent d'utiliser le typedef pour une variable de classe et pas pour l'autre.

rating est une variable de classe, mais vous semblez seulement l'utiliser comme un détenteur temporaire dans vos deux fonctions. Si c'est votre usage prévu, il serait préférable d'utiliser simplement une variable locale dans les deux fonctions.

Vous n'avez jamais delete les objets Rating que vous placez dans vos cartes. Si les cartes doivent posséder les objets Rating, il sera alors plus facile d'avoir un std::map<int, Rating> de manière à ce que vous n'ayez pas à effectuer de suppression manuelle. Il ne semble pas que Rating soit conçu pour être un appel de base, c'est une classe de valeur telle quelle.

+0

Bonjour, Merci pour vos suggestions. En fait, je voulais faire de repTable un global et fHandInfo un local, mais peut-être que je ne l'ai pas fait correctement. (1) Si je veux utiliser Rating * et assigner de la mémoire en utilisant 'new', alors quel est un bon moyen de libérer de la mémoire de Rating *? (2) Quelle est la vraie raison du conflit qui cause la faute de seg_ car je peux l'exécuter en utilisant ces fonctions individuellement? Merci –

+0

Bien _undefined behavior_ signifie que tout peut arriver. Donc, vous pouvez faire quelque chose de mal, mais vous ne pouvez pas voir de mauvais effets tout droit. Dans votre implémentation particulière, l'itérateur de fin pour un conteneur vide peut ne pas pointer quelque part qui provoque quelque chose de mal se produire lorsque vous le déréférencer après l'insertion. Cependant, vous ne pouvez pas compter sur ceci donc vous étiez juste (un) chanceux que cela a fonctionné une fois. –

+0

Tout objet que vous allouer avec 'new' devrait être supprimé exactement une fois en utilisant l'opérateur' delete' sur un pointeur pointant vers cet objet. –

2
it = repTable.find(address); 
if (it == repTable.end()){ 
cout << "Adding New Entry for (repTable) "<< address <<endl; 
rating = new Rating(); 
repTable[address] = rating; 
} 
(it->second)->updateRep(behaviour); 

// Lorsque l'adresse ne se trouve pas sur la carte, puis après l'insertion du iterator it ne sera pas automatiquement des points // à l'élément nouvellement inséré. Par conséquent, (it-> second) est UB.

Vous pouvez modifier un peu le code:

Rating* rating = NULL; 
map<int, Rating*>::iterator it = repTable.find(address); 
if (it == repTable.end()) 
{ 
rating = new Rating(); 
repTable[address] = rating; 
} 
else 
{ 
rating = it->second; 
} 

Indice d '> updateRep (comportement);

0

Les erreurs Seg sont généralement dues au fait que vous tentez d'accéder à un objet qui n'a pas été alloué.

Dans votre code, vous appelez le constructeur à l'intérieur d'un bloc IF().

if (it == repTable.end()){ 
    cout << "Adding New Entry for (repTable) "<< address <<endl; 
    rating = new Rating(); 
    repTable[address] = rating; 
} 

Si vous essayez d'accéder à repTable [adresse] et qu'il n'y a pas d'objet, une exception instantanée. Essayez de le placer dans un bloc catch et imprimez les détails de l'exception. Cela pourrait vous donner plus d'informations sur la structure qui cause un problème.

+1

Mais 'std :: map :: operator []' insère un élément s'il n'en existe pas un et renvoie une référence à la partie valeur de l'objet. –

+0

Je pensais au cas général d'attendre que chaque élément d'une collection soit non nul, puis essaye d'appeler une méthode sur un élément qui est en fait un pointeur nul. –

1

Légèrement sans rapport avec la segfault, mais un problème qui empêche votre exemple de fonctionner correctement: dans votre fonction principale, vous déclarez address et vous ne le définissez pas avant de l'utiliser.

 
int main() { 
    int address;  
    RepSys repsys; 
    while (address != 0) 
    { 
// ... 
    } 

Sur la première manche, en fonction de votre compilateur, vous ne savez pas ce que la valeur de address est. Au début, je ne pourrais pas obtenir votre exemple à segfault, puisque mon compilateur a initialisé l'adresse à 0 et il sauterait simplement la boucle et sortirait.

Assurez-vous d'initialiser vos variables avant de les utiliser.