0

しばらく時間と労力を費やした後、コード内のメモリ破壊バグをこの関数に突き止めました。__block vector<int>2 つの変数を、ストレージを提供するスタック割り当て配列と、ブロック内のコードが配列にアクセスできるようにする変数の組み合わせに置き換えることで、メモリ破壊を止めました{klist|dlist}Ptr(以下の推奨コードを参照)。これは、実際に問題があるのは の使用であると確信しています__block vector<int>

void
traceTree(Matrix<double> Z, double s[3], int k, unsigned int depth)
{
    int m = Z.size(1) + 1;
    __block vector<int> klist(m, 0);
    // int klist[m]; int * klistPtr = klist;
    // klist[0] = k;
    __block vector<int> dlist(1, depth);
    // int dlist[depth]; int * dlistPtr = dlist;
    // dlist[0] = depth;
    __block int topk = 0;
    int currk = 0;

    void (^ subtree)(int i) = ^(int i) {
        if (i > m) {                // If it's not a leaf...
            topk += 1;
            klist[topk] = i - m;
            dlist[topk] = depth - 1;
        }
    };

    while (currk <= topk) {
        k = klist[currk];
        depth = dlist[currk];
        s[0] += Z[{2,k}];            // Sum of the edge lengths so far
        s[1] += Z[{2,k}] * Z[{2,k}]; // ... and the sum of the squares
        s[2] += 1;                   // ... and the count of the edges
        if (depth > 0) {
            subtree(Z[{0,k}]);       // Consider left subtree
            subtree(Z[{1,k}]);       // Consider right subtree
        }
        currk += 1;
    }
}

[指摘しておきますが、これは純粋に反復的なアルゴリズムです。再帰はありません。このブロックは、左右のサブツリーを処理するために必要なコードの重複を避けるためにのみ存在します。]

明らかな疑問は、なぜ STLvectorオブジェクトがここでメモリ破損を引き起こしているのかということです。__block彼らは動的なサイズ変更すら行っていません... C++ オブジェクトを変数として使用することは単にサポートされていないのでしょうか?

4

2 に答える 2

1

dlistタイプミスでない限り、 の初期化が配列とは異なることがわかります。vector<int> dlist(1, depth);ではなく、長さ 1 のベクトルを作成しdepthます。これにより、範囲外になる可能性があります。

読み取りと書き込みの両方dlist.at(currk)に の代わりに を使用することで、範囲外のベクトル要素へのアクセスを常に防ぐことができます。dlist[currk]

于 2013-04-08T20:25:12.733 に答える