0

经过一段时间和努力,我在我的代码中找到了这个函数的内存破坏错误。__block vector<int>我通过将两个变量替换为堆栈分配数组的组合来提供存储空间和一个{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;
    }
}

[我应该指出,这是一个纯粹的迭代算法;没有递归。该块的存在只是为了避免重复处理左右子树所需的代码。]

The obvious question is, why are the STL vector objects causing memory corruption here? They are not even doing any dynamic resizing… Is it simply not supported to use a C++ object as a __block variable?

4

2 回答 2

1

Unless it's a typo, I see your initialization of dlist being different from the array: vector<int> dlist(1, depth); makes a vector of length 1, not depth. This may possibly cause going out of bounds.

You can always guard against accessing vector elements out of bounds by using dlist.at(currk) instead of dlist[currk], for both reading and writing.

于 2013-04-08T20:25:12.733 回答
0

C++ objects are allowed as __block variables (though personally I would recommend lambdas if you're writing C++; there's not much reason IMO to use blocks in pure C++ like this).

__block C++ variables are copied using the copy constructor (see C++ Objects in Block Programming Topics). It's possible you're overflowing your stack due to too many copies of large stack variables if this goes very deep (that would match your "memory corruption" symptom).

But again, I'd recommend lambdas rather than blocks for C++; see @sellibitze's answer at How do Clang 'blocks' work? for some more discussion.

于 2013-04-08T02:44:38.197 回答