2010-01-05 3 views
0

Я определил класс с именем nth_best_parse таким образом:C++ vector push_back() перезаписывает другой вектор того же типа?

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;} 
    }; 

Тогда я объявил векторы этого nth_best_parse в качестве членов двух различных классов:

class Edge {  // an edge associates an Earley style dotted-item with a span 
     public: 

     <some irrelevant stuff> 

     Span span;  // Span of the edge 
     bool isActive; 
     vector<Traversal *> leading_traversals; // The list of traversals which lead to parsing of this edge 

     vector<nth_best_parse> n_best_parses; 


     union { 
       DottedRule rule_state; // Accessed if isActive is true 
       int symbol;  // Accessed if isActive is false 
           // A symbol corresponding to the category of a passive edge 
           // Put inside this union to save space 
     }; 

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

    }; 

<some other stuff> 

class BPCFGParser { 

    public: 

    // Some data structures used in intermediary computations for calculating the n-best parses 

// vector<vector<int> > nth_best_pairs; 
    vector<vector<nth_best_parse> > n_best_pairs_for_traversals; 

    <some other stuff> 

    void compute_n_best_parses(Edge *e, int n); 

    <some other stuff> 
} 

Затем я запустить эту программу с помощью GDB (кстати, , Я использую Linux Ubuntu 9.04, g ++ 4.3.3, GNU gdb 6.8-debian) и установить точку останова в конце определения compute_n_best_parses() с некоторыми условиями (чтобы найти точный вызов этой функции, которую я хотел, я отскакивает назад от ошибки сегментации). Когда GDB ударил точки останова, я выпустил набор команд и вывода GDB было так:

(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 = {<std::_Vector_base<nth_best_parse, std::allocator<nth_best_parse> >> = { 
    _M_impl = {<std::allocator<nth_best_parse>> = {<__gnu_cxx::new_allocator<nth_best_parse>> = {<No data fields>}, <No data fields>}, 
     _M_start = 0x1e96240, _M_finish = 0x1e96258, _M_end_of_storage = 0x1e96288}}, <No data fields>} 
(gdb) continue 
Continuing. 
Hardware access (read/write) watchpoint 6: *$30 

Old value = 0 
New value = 1 
0x0000000000408a4c in __gnu_cxx::new_allocator<nth_best_parse>::construct<nth_best_parse> (this=0x1e96208, __p=0x1e96240, __args#[email protected]) 
    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<nth_best_parse>::construct<nth_best_parse> (this=0x1e96208, __p=0x1e96240, __args#[email protected]) 
    at /usr/include/c++/4.3/ext/new_allocator.h:114 
#1 0x000000000042169c in std::vector<nth_best_parse, std::allocator<nth_best_parse> >::push_back<nth_best_parse> (this=0x1e96208, __args#[email protected]) 
    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 

Line 639 BPCFGParser.cpp было так:

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

Это макрос, определенный в начало файла, как:

#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)) 

Кстати, класс Traversal определяется как:

class Traversal { // Class for a traversal 
     public: 
     Edge *active_edge; 
     Edge *passive_edge; 
     Traversal(); 
     Traversal(Edge *a, Edge *p) {active_edge = a; passive_edge = p;} 
    }; 

Так что я нажимаю что-то на вектор n_best_pairs_for_traversals, который является членом экземпляра класса BPCFGParser, а код push_back() как-то перезаписывает вектор n_best_parses, который является членом экземпляра класса Край. Как это возможно?

+0

Я бы рекомендовал вам попробовать упростить свое репо –

ответ

1

Вы уверены, что передаете действительный первый аргумент своему макросу? Возможно, вы получаете доступ за пределы, когда делаете n_best_pairs_for_traversals[x], потому что x больше размера вектора.

+0

Да! Фактически я это проверил, но я думаю, что я не был достаточно осторожен.Так или иначе, это не привело к сбою сегментации и произошла ошибка памяти. Спасибо за помощь. –

+0

Вы можете использовать метод at() вместо оператора [] для более легкого обнаружения таких проблем. Он проверяет, не вышли ли из-за пределов и выбрасываете исключение, вместо того, чтобы вызывать неопределенное поведение. Очевидно, что стоимость исполнения. –

5

У вас, очевидно, проблемы с повреждением памяти.
НО, здесь информации недостаточно, чтобы помочь вам.

Но вы пишете код C++, и ваш класс содержит указатели.
Это не хороший знак (вряд ли когда-либо будет RAW-указатель в классе C++).
Это также часто является причиной повреждения памяти для неопытных разработчиков на C++!

Вы повиновались правилу 4?

Убедитесь, что каждый класс, который содержит RAW принадлежат указатели:

  • конструктор
  • конструктор копирования
  • оператор присваивания
  • деструктор.
0

Я бы предположил, что вы используете вектор для хранения объектов (возможно, Traversal?), Не понимая, что толкание новых элементов на этот вектор может привести к недействительности указателей на элементы, уже находящиеся в векторе. Вместо этого используйте deque, если это так.

+0

Векторы хранят объекты типа nth_best_parse, а не Traversal. Вектор, на обратной стороне которого я нажимаю новый объект, и вектор, переписанный, - разные векторы. –

+0

ОК, но вы не можете смотреть векторный элемент, если вы добавляете элементы в вектор. Базовый массив может быть перераспределен, поэтому ваш наблюдаемый адрес больше не указывает на нужный элемент. Дека действительно гарантирует, что нет перераспределения, когда элементы только добавляются в конец. – ergosys

+0

Конечно, это может быть не связано с повреждением векторов. Вы видели эту проблему, используя другой метод отладки? – ergosys

Смежные вопросы