在使用std向量为我的国际象棋引擎保存移动列表后,我意识到,由于国际象棋的平均因数为35 (大约从一个典型位置移动到35次合法移动),该向量正在调整大小,从而对移动生成器的性能产生负面影响。解决这个问题的一种方法(我今天才意识到)是为向量保留最小容量。然而,使用alloca()的可能性引起了我的注意。这可能是一个非常简单的问题,但是关于alloca()的文档非常稀少,很少有如何使用它的例子。
因此,Allocation of variable-sized class的答复提到不能调整堆栈分配的大小。然而,以下内容是否有效?
struct MoveList
{
MoveList(): capacity(10)
{
moves = (Move*) alloca(sizeof(Move) * 10);
}
void resize()
{
capacity *= 2;
moves = (Move*) alloca(sizeof(Move) * capacity );
}
void push_back();
Move* moves;
int size;
int capacity;
}具体来说,如果第一次从alloca()获得10的容量是不够的,那么再次调用alloca()来分配更多内存是否在语法上是有效的(并且是正确的)?这种方法会提供更好的性能(与保留()的std向量相比),还是只会增加堆栈溢出的可能性?我的移动结构需要大约28字节的内存,我怀疑引擎会递归地搜索(使用alpha-beta)到可能最大的7或8层,这样可能会从堆栈中使用大约28 * 35 *8~ 8kb的最大值。我在某个地方读到,典型的堆栈有1Mb的限制,所以这不应该太多,对吗?
编辑:感谢下面的答案,我现在意识到我对alloca()所做的事情的最初理解是错误的。但是,我仍然想知道是否可以以以下方式使用alloca():
int main()
{
int* arr = (int) alloca(sizeof(int));
arr = alloca(sizeof(int) * 2 ));//is this 'resizing' valid?
}发布于 2014-06-06 12:44:54
函数alloca在堆栈上分配内存,一旦调用alloca的函数返回,内存就不再可用。这意味着,一旦MoveList构造函数或resize函数返回,内存就不再可用。您认为可以在MoveList对象的生命周期内使用此内存的假设是错误的。
对您来说最好的选择是使用std::vector和预订。
发布于 2014-06-06 12:53:12
您似乎不明白非标准的alloca()表达式实际上是做什么的。它在调用函数的堆栈帧中分配内存。在您的示例中,这意味着分配给moves成员的空间的生存期是构造函数的生存期:
MoveList(): capacity(10)
{
moves = (Move*) alloca(sizeof(Move) * 10);
... moves is valid from this point
// "moves" stops being valid at this point
}因为其余的构造函数是空的,所以这是而不是。(此外,alloca()还有一个副作用,即防止调用函数内联--另一个意外的副作用。)换句话说,为了回答标题中的问题,alloca()的这种用法是无效的。
即使它在某种程度上是有效的,因为alloca()没有相应的对象来调整或释放分配的内存(由于它的工作方式,它也不能有一个内存),对于任何需要调整区域大小的情况,这都是非常不合适的--这正是您试图使用它的方式。
std::vector的调整容量通常已经成为指数增长的因素,因此添加您自己的能力是不必要的。如果你不确定,衡量性能,看看什么对你有用。对于您的情况,只需调用std::vector<T>::reserve()就可以确保向量以乐观的大小开始,从而消除了重新分配的需要。或者使用std::deque,它从不重新分配元素(代价是访问速度稍慢)。
https://stackoverflow.com/questions/24082061
复制相似问题