0

この方法で nth_best_parse という名前のクラスを定義しました。

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 のベクトルを 2 つの異なるクラスのメンバーとして宣言しました。

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#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<nth_best_parse>::construct<nth_best_parse> (this=0x1e96208, __p=0x1e96240, __args#0=@0x7fff8ad82260)
    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#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

BPCFGParser.cpp の 639 行目は次のようになりました。

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

したがって、実際には、クラス BPCFGParser のインスタンスのメンバーであるベクトル n_best_pairs_for_traversals に何かをプッシュしています。push_back() コードは、クラス Edge のインスタンスのメンバーであるベクトル n_best_parses を上書きします。どうしてこれが可能になるのでしょうか?

4

3 に答える 3

5

You obviously have memory corruption problems somewhere.
BUT there is not enough here information to help you.

But you are writing C++ code and your class contain pointers.
This is not a good sign (there should hardly ever be a RAW pointer in a C++ class).
This is also often the cause of memory corruption for inexperienced C++ developers!

Have you obeyed the rule of 4?

Make sure every class that contains RAW owned pointers:

  • constructor
  • copy constructor
  • assignment operator
  • destructor.
于 2010-01-05T20:04:26.507 に答える
1

Are you sure you're passing a valid first argument to your macro? Maybe you're accessing out of bounds when doing n_best_pairs_for_traversals[x] because x is larger than the vector size.

于 2010-01-05T20:00:57.797 に答える
0

ベクトルを使用してオブジェクト(おそらくトラバーサル?)を格納していると思いますが、そのベクトルに新しい要素をプッシュすると、既にベクトルにある要素へのポインターが無効になる可能性があることに気づいていません。この場合は、代わりに両端キューを使用してください。

于 2010-01-05T20:33:31.443 に答える