经过一段时间和精力后,我在我的代码中找到了一个内存粉碎错误的函数。我通过使用堆栈分配的数组的组合替换两个__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;
}
}
[我应该指出,这是一个纯粹的迭代算法;没有递归。存在该块只是为了避免重复处理左右子树所需的代码。]
显而易见的问题是,为什么STL vector
对象导致内存损坏?他们甚至没有进行任何动态调整大小...是否根本不支持将C ++对象用作__block
变量?
答案 0 :(得分:1)
除非是拼写错误,否则我看到dlist
的初始化与数组不同:vector<int> dlist(1, depth);
生成长度为1的向量,而不是depth
。这可能会导致超出范围。
您可以使用dlist.at(currk)
代替dlist[currk]
来防止访问向量元素超出范围,无论是阅读还是写作。
答案 1 :(得分:0)
C ++对象被允许作为__block
变量(虽然如果你正在编写C ++,我个人会推荐lambdas; IMO在纯C ++中使用块的原因并不多见。)
__block
使用复制构造函数复制C ++变量(请参阅块编程主题中的C++ Objects)。由于大量堆栈变量的副本太多而非常深(这与您的“内存损坏”症状相符),您可能会溢出堆栈。
但是,我再次推荐使用lambdas而不是C ++的块;请参阅@sellibitze's answer How do Clang 'blocks' work?进行更多讨论。