这个alloca()的使用是否有效?

时间:2014-06-06 12:38:25

标签: c++ alloca

使用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()以分配更多内存在语法上是否有效(并且正确)? 这个方法会提供更好的性能(与带有reserve()的std向量相比),还是只增加堆栈溢出的可能性?我的Move结构需要大约28个字节的内存,我怀疑引擎将递归搜索(使用alpha-beta)到最大7或8层,这样可能会从堆栈中使用最大28 * 35 * 8~8kb max。我读到某处通常堆栈的限制为1Mb,所以这不应该太多了吗?

编辑:感谢下面的答案,我现在意识到我对alloca()所做的最初的理解是错误的。但是,我仍然想知道是否可以以下面的方式使用alloca():

    int main()
    {
        int* arr = (int) alloca(sizeof(int));
        arr = alloca(sizeof(int) * 2 ));//is this 'resizing' valid?
    }

2 个答案:

答案 0 :(得分:3)

函数alloca在堆栈上分配内存,并且只要调用alloca的函数返回,内存就不再可用。这意味着只要MoveList构造函数或resize函数返回,内存就不再可用。您假设在MoveList对象的生命周期内以某种方式使用此内存是错误的。

最好的选择是使用std::vector并保留。

答案 1 :(得分:1)

您似乎无法理解非标准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,它永远不会重新分配元素(以稍慢的访问速度为代价)。