0 votes

C++ vector push_back() écrase-t-il un autre vecteur du même type ?

J'ai défini une classe nommée nth_best_parse de cette manière :

class nth_best_parse {
      public:
        int traversal;
        int nth_best_active;
        int nth_best_passive;
        double viterbi_prob;

        nth_best_parse();
        nth_best_parse(int t, int nbl, int nbr, double v) {traversal = t; nth_best_active = nbl; nth_best_passive = nbr; viterbi_prob = v;}
    };

Ensuite, j'ai déclaré des vecteurs de cet nth_best_parse en tant que membres de deux classes différentes :

class Edge {        // un edge associe un élément pointé de style Earley avec une étendue
      public:

        Span span;      // Span de l'edge
        bool isActive;
        vector leading_traversals; // La liste des traversées qui mènent à l'analyse de cet edge

        vector n_best_parses;

        union {
                DottedRule rule_state;  // Accédé si isActive est vrai
                int symbol;     // Accédé si isActive est faux
                                // Un symbole correspondant à la catégorie d'un edge passif
                                // Mis à l'intérieur de cette union pour économiser de l'espace
        };

        inline int span_length() {return span.end - span.start;}

    };

class BPCFGParser {

  public:

    // Certaines structures de données utilisées dans des calculs intermédiaires pour calculer les meilleures analyses n

//    vector > nth_best_pairs;
    vector > n_best_pairs_for_traversals;

    void compute_n_best_parses(Edge *e, int n);

}

Ensuite, j'ai exécuté ce programme avec gdb (au fait, j'utilise Linux Ubuntu 9.04, g++ 4.3.3, GNU gdb 6.8-debian) et j'ai placé un point d'arrêt à la fin de la définition de compute_n_best_parses() avec quelques conditions (pour localiser l'appel exact de cette fonction que je voulais, je remontais à partir d'une erreur de segmentation). Lorsque gdb a atteint le point d'arrêt, j'ai lancé une série de commandes et la sortie gdb était ainsi :

(gdb) print e->n_best_parses.size()
$27 = 1
(gdb) print e->n_best_parses[0]
$28 = (nth_best_parse &) @0x1e96240: {traversal = 0, nth_best_active = 0, nth_best_passive = 0, viterbi_prob = 0.16666666666666666}
(gdb) print e->n_best_parses[0].traversal
$29 = 0
(gdb) print &(e->n_best_parses[0].traversal)
$30 = (int *) 0x1e96240
(gdb) awatch *$30
Hardware access (read/write) watchpoint 6: *$30
(gdb) print e->n_best_parses
$31 = { >> = {
    _M_impl = {> = {<__gnu_cxx::new_allocator> = {}, }, 
      _M_start = 0x1e96240, _M_finish = 0x1e96258, _M_end_of_storage = 0x1e96288}}, }
(gdb) continue
Continuing.
Hardware access (read/write) watchpoint 6: *$30

Ancienne valeur = 0
Nouvelle valeur = 1
0x0000000000408a4c in __gnu_cxx::new_allocator::construct (this=0x1e96208, __p=0x1e96240, __args#0=@0x7fff8ad82260)
    at /usr/include/c++/4.3/ext/new_allocator.h:114
114     { ::new((void *)__p) _Tp(std::forward<_Args>(__args)...); }
(gdb) backtrace
#0  0x0000000000408a4c in __gnu_cxx::new_allocator::construct (this=0x1e96208, __p=0x1e96240, __args#0=@0x7fff8ad82260)
    at /usr/include/c++/4.3/ext/new_allocator.h:114
#1  0x000000000042169c in std::vector >::push_back (this=0x1e96208, __args#0=@0x7fff8ad82260)
    at /usr/include/c++/4.3/bits/stl_vector.h:703
#2  0x0000000000402bef in BPCFGParser::compute_n_best_parses (this=0x7fff8ad82770, e=0x7f5492858b78, n=3) at BPCFGParser.cpp:639
#3  0x00000000004027fd in BPCFGParser::compute_n_best_parses (this=0x7fff8ad82770, e=0x7f5492859d58, n=3) at BPCFGParser.cpp:606
#4  0x00000000004027fd in BPCFGParser::compute_n_best_parses (this=0x7fff8ad82770, e=0x7f549285a1d0, n=3) at BPCFGParser.cpp:606
#5  0x00000000004064d8 in main () at experiments.cpp:75

La ligne 639 de BPCFGParser.cpp était comme ceci :

PUSH_BEST_PAIR_FOR_TRAVERSAL(i,row,column,grammar->probs[temp_rule.symbol][temp_rule.expansion]);

C'était un macro défini au début du fichier comme ceci :

#define PUSH_BEST_PAIR_FOR_TRAVERSAL(x,y,z,t) n_best_pairs_for_traversals[x].push_back(nth_best_parse(x, y, z, e->leading_traversals[x]->active_edge->n_best_parses[y].viterbi_prob * e->leading_traversals[x]->passive_edge->n_best_parses[z].viterbi_prob * t))

Au fait, la classe Traversal est définie comme :

class Traversal {   // Classe pour une traversée
      public:
        Edge *active_edge;
        Edge *passive_edge;
        Traversal();
        Traversal(Edge *a, Edge *p) {active_edge = a; passive_edge = p;}
    };

En réalité, je pousse quelque chose dans le vecteur n_best_pairs_for_traversals, qui est un membre d'une instance de la classe BPCFGParser et le code push_back() écrase d'une manière ou d'une autre sur le vecteur n_best_parses, qui est un membre d'une instance de la classe Edge. Comment cela est-il possible ?

5voto

Loki Astari Points 116129

Vous avez clairement des problèmes de corruption de mémoire quelque part.
MAIS il n'y a pas suffisamment d'informations ici pour vous aider.

Mais vous écrivez du code C++ et votre classe contient des pointeurs.
Ce n'est pas bon signe (il ne devrait presque jamais y avoir un pointeur RAW dans une classe C++).
C'est aussi souvent la cause de la corruption de mémoire pour les développeurs C++ inexpérimentés!

Avez-vous respecté la règle des 4?

Assurez-vous que chaque classe contenant des pointeurs en propriété RAW:

  • constructeur
  • constructeur de copie
  • opérateur d'affectation
  • destructeur.

0voto

Nicolás Points 4959

Êtes-vous sûr de passer un premier argument valide à votre macro? Peut-être que vous accédez à des éléments hors limites en faisant n_best_pairs_for_traversals[x] car x est plus grand que la taille du vecteur.

0voto

ergosys Points 15343

Je suppose que vous utilisez un vecteur pour stocker des objets (peut-être Traversal?), sans réaliser que pousser de nouveaux éléments sur ce vecteur peut invalider des pointeurs vers des éléments déjà dans le vecteur. Si c'est le cas, utilisez plutôt une deque.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X