2015-03-28 4 views
0

Je suis en train d'écrire un programme qui traite des lots de mises à jour dans un graphe au sein de nouveaux nœuds et arêtes. J'ai récemment intégré un schéma de fenêtre glissante qui vérifie si les bords déjà dans le graphique sont dans la fenêtre, et sinon les supprime. J'utilise un bord et la classe Node comme suit:Récupération d'une erreur de segmentation dans un programme de traitement de flux de données

class Edge 
{ 
public: 
uint64_t source; 
uint64_t target; 
unsigned type; 
std::string label; 
uint64_t timestamp; 
bool directed; 
bool extracted; 
Edge(){} 
Edge(Edge *e); 
Edge(uint64_t, uint64_t, unsigned, std::string, time_t, bool); 
bool operator ==(const Edge *other) 
    { 
    return((this->source==other->source)&&(this->target==other->target)&& \ 
      (this->type==other->type)); 
    } 
}; 

class Node 
{ 
    public: 
    uint64_t id; 
    unsigned type; 
    std::string label; 
    uint64_t timestamp; 
    std::vector<Edge *> adjacent_edges; 
    Node(){} 
    Node(Node *); 
    bool push_edge(Edge *e) 
    { 
    try 
    { 
    adjacent_edges.push_back(e); 
    } 
    catch(std::bad_alloc&) 
    { 
    std::cout<<"Error pushing edge"<<std::endl; 
    return false; 
    } 
    return true;  
    } 

    std::vector<Edge *>::iterator pop_edge(std::vector<Edge *>::iterator e_it) 
    { 
    return adjacent_edges.erase(e_it); 
    } 

    bool operator ==(const Node *other) 
    { 
    return (this->id == other->id); 
    } 
}; 

En utilisant un ensemble de données que je reçois une erreur de segmentation après traitement 69 fichiers batch avec une taille de fenêtre coulissante de 5 tout en essayant d'accéder à un bord à l'aide d'un itérateur de bord. En utilisant un autre ensemble de données, je reçois une erreur de segmentation après 69 fichiers batch en essayant de supprimer un pointeur Edge non vide dans la liste d'adjacence (essayant de libérer la mémoire). Je suis à bout de nerfs en essayant de comprendre ce qui ne va pas. La version de fenêtre non-glissante de ce programme fonctionne très bien. Je sais aussi que l'utilisation d'une structure de données STL Deque serait préférable pour les fenêtres coulissantes. Cependant, je travaille avec un code assez volumineux, et j'aimerais pouvoir le résoudre sans avoir à utiliser une deque. Merci d'avance. Edit: Il arrive sur deux lignes différentes:

for (int i = 0; i < node_list.size(); i++) 
    { 
    vector<Edge *>::iterator adj_it; 

    for (adj_it = (node_list[i])->adjacent_edges.begin(); adj_it != (node_list[i])->adjacent_edges.end(); ++adj_it) 
    { 


     if ((max_batch_num - (*adj_it)->timestamp) > time_window) 
     { 


      deleteEdge(adj_it); 
      num_edges_deleted++; 
      --adj_it; 

     } 

    } 

} 

Il arrive sur la ligne:

if ((max_batch_num - (*adj_it)->timestamp) > time_window) 

sur l'utilisation du premier ensemble de données. Le problème ici est que même si le vecteur n'est pas vide, les pointeurs du vecteur pointent vers une mémoire qui ne fait pas partie de l'application. Quand j'utilise gdb pour tenter d'imprimer:

print (*adj_it)->timestamp 

donne: Tentative de prendre l'adresse de la valeur dans la mémoire non

Cela ne devrait pas se produire si que les bords sont ajoutés à la liste de contiguïté. Et sur l'utilisation du second ensemble de données l'erreur se produit lors de l'utilisation:

delete (*adj_it); 

où adj_it est un itérateur pour le vecteur de adjacency_list. Ce qui est aussi bizarre, c'est que si j'augmente la fenêtre glissante en disant 'n', le même problème se produit après 'n' lots.

Ajout de la fonction deleteEdge:

vector<FSM::Edge *>::iterator FSM::Graph::deleteEdge(vector<Edge *>::iterator e_it) 
{ 
//cout<<"Deleting edge: e "<<e->source<<" -> "<<e->target<<endl;//DEBUG 
FSM::Node *s = getNode((*e_it)->source); 
FSM::Edge *e_tmp = (*e_it); 
e_it = s->pop_edge(e_it); 
if (e_tmp != NULL) 
{ 
    delete e_tmp; 
} 
else 
{ 
    std::cerr<<"Trying to delete an Edge pointer which is NULL"<<endl; 
    exit(1); 
} 
return e_it; 

}

Aussi je l'ai déjà utilisé que des index, et je l'ai essayé à nouveau après la réponse de @Julius. C'est ma nouvelle boucle de suppression.

for (int j = 0; j<(node_list[i])->adjacent_edges.size();j++) 
    { 
     if ((max_batch_num - ((node_list[i])->adjacent_edges[j])->timestamp) > time_window) 
       {      
        (node_list[i])->adjacent_edges.erase((node_list[i])->adjacent_edges.begin() + j); 
        --j; 
        num_edges_deleted++; 

       } 

    } 

Cependant, je reçois les mêmes erreurs malgré tout.

BTW. J'apprécie vraiment tous les commentaires jusqu'à présent. Merci pour votre temps. Editer: La mémoire trouvée fuit dans une partie différente du code en utilisant valgrind. Se débarrasser de ce code (ce n'était pas vraiment nécessaire à l'algorithme) s'en est débarrassé. J'accepte la réponse de @Julius car cela aurait résolu le problème selon ma déclaration d'origine. Merci également à @RetiredNinja, @Beta et @Golazo pour leurs excellents commentaires.

+0

Quelle ligne cela arrive-t-il? –

+1

Si vous avez des problèmes de mémoire, la première chose à faire est de se débarrasser des pointeurs propriétaires –

+3

Il est temps d'exécuter votre débogueur. –

Répondre

0
for (int i = 0; i < node_list.size(); i++) 
    { 
    vector<Edge *>::iterator adj_it; 

    for (adj_it = (node_list[i])->adjacent_edges.begin(); adj_it != (node_list[i])->adjacent_edges.end(); ++adj_it) 
    { 


     if ((max_batch_num - (*adj_it)->timestamp) > time_window) 
     { 


      deleteEdge(adj_it); 
      num_edges_deleted++; 
      --adj_it; 

     } 

    } 

} 

vous supprimez le bord, puis revenir en arrière avec --adj_it, puis itérer en arrière sur le bord que vous venez de supprimer avec deleteEdge parce que la boucle For ++ adj_it. Vous essayez ensuite de vérifier l'objet timestamp d'un objet Edge supprimé (non valide), ce qui provoque le segfault. Soit cela ou vous supprimez l'objet du vecteur Edge *, puis invalidez votre itérateur.

La partie importante est que les itérateurs ne sont pas des index. Vous ne pouvez pas simplement effacer un élément, puis faire --adj_it. Voici un cas où l'utilisation d'un index serait plus facile, car vous pourriez juste supprimer l'objet de bord, enlever le pointeur de bord du vecteur, puis continuer la boucle après avoir fait --adj_it comme vous le faites. Les itérateurs sont juste plus lents que les index sur les vecteurs btw.

+0

Je revenais en arrière, car j'utilise la méthode d'effacement vectoriel, qui supprime le bord de la liste adjacency_list et ramène ensuite tous les autres éléments à la suite. Le commentaire de @ RetiredNinja dit que c'était faux car erase renvoie un nouvel itérateur et je ne peux pas utiliser l'itérateur précédent pour aller à l'élément précédent. J'espère que j'ai bien compris votre réponse. – rayabhik

+0

J'utilisais un index auparavant, et je l'ai essayé à nouveau. Même erreur Ce que je ne peux pas comprendre, c'est que si la taille de adjacent_edge n'est pas 0, comment peut-il y avoir des pointeurs là-bas qui pointent vers une mémoire illégale. Surtout que ce bord a été ajouté dans le lot précédent. – rayabhik

+0

La réponse simple à pourquoi il pourrait y avoir des éléments invalides dans le vecteur est que d'une certaine façon votre code les y a mis.Les pointeurs bruts sont dangereux, et il n'y a aucune garantie que vous ne supprimiez pas quelque chose en double ou que vous ne fassiez simplement que de mauvaises choses. –