对可变长度数组使用 alloca() 是否比在堆上使用向量更好?

Is using alloca() for variable length arrays better than using a vector on the heap?

我有一些使用可变长度数组 (VLA) 的代码,它在 gcc 和 clang 中编译良好,但不适用于 MSVC 2015。

class Test {
public:
    Test() {
        P = 5;
    }
    void somemethod() {
        int array[P];
        // do something with the array
    }
private:
    int P;
}

代码中好像有两种解决方法:

ector 会更便携(更少 #ifdef 测试使用哪个编译器),但我怀疑 alloca() 更快。

矢量实现如下所示:

class Test {
public:
    Test() {
        P = 5;
        init();
    }
    void init() {
        array.resize(P);
    }
    void somemethod() {
        // do something with the array
    }
private:
    int P;
    vector<int> array;
}

另一个考虑因素:当我只在函数外更改 P 时,在堆上有一个数组而不是在堆栈上重新分配比在堆栈上有一个 VLA 更快吗?

最大P会在400左右

您可以而且可能应该使用一些动态分配的 heap memory, such as managed by a std::vector (as )。您可以使用智能指针或普通原始指针 (new, malloc,..),您不应忘记释放它们 (delete,free,.. ..).请注意,堆分配可能比您认为的要快(实际上,在大多数情况下,当前笔记本电脑的速度不到一微秒)。

有时你可以将分配移出一些内部循环,或者只是偶尔增加它(所以对于 realloc-like 事情,更好地使用 unsigned newsize=5*oldsize/4+10; 而不是 unsigned newsize=oldsize+1; 即一些几何增长)。如果您不能使用向量,请确保将分配的大小和使用的长度分开(正如 std::vector 在内部所做的那样)。

另一种策略是特例小尺寸与大尺寸。例如对于少于 30 个元素的数组,使用调用堆栈;对于更大的,使用堆。

如果你坚持分配(在Linux上使用VLAs -they are a commonly available extension of standard C++11- or alloca) on the call stack, be wise to limit your call frame to a few kilobytes. The total call stack is limited (e.g. often to about a megabyte or a few of them on many laptops) to some implementation specific limit. In some OSes you can raise that limit (see also setrlimit(2)

请务必在手动调整代码之前进行基准测试。不要忘记启用 compiler optimization (e.g. g++ -O2 -Wall with GCC) before benchmarking. Remember that caches misses 通常比堆分配昂贵得多。不要忘记开发人员的时间也有一些成本(这通常与累积的硬件成本相当)。

请注意,使用 static variable or data has also issues (it is not reentrant, not thread safe, not async-signal-safe -see signal-safety(7) ....) 且可读性较差且鲁棒性较差。

首先,如果您的代码可以按原样使用任何 C++ 编译器进行编译,那么您就很幸运了。 VLA 不是标准的 C++。 Some compilers 支持它们作为扩展。

使用 alloca() 也不是标准的,因此不能保证在使用不同的编译器时可靠地工作(甚至根本不能)。

在许多情况下不建议使用 static 向量。在您的情况下,它给出的行为可能不等同于原始代码。

您可能希望考虑的第三个选项是

 // in definition of class Test
void somemethod()
{
    std::vector<int> array(P);      // assume preceding #include <vector>
    // do something with array
}

vector本质上是一个动态分配的数组,但是在上面的函数returns.

中会被正确清理

以上是标准的C++。除非您执行严格的测试和分析来提供性能问题的证据,否则这应该就足够了。

为什么不将数组设为私有成员?

#include <vector>

class Test
{
public:
    Test()
    {
        data_.resize(5);
    }
    void somemethod()
    {
        // do something with data_
    }
private:
    std::vector<int> data_;
}

因为您已经指定了数组的可能最大大小,您还可以查看类似 boost::small_vector 的内容,它可以像这样使用:

#include <boost/container/small_vector.hpp>

class Test
{
public:
    Test()
    {
        data_.resize(5);
    }
    void somemethod()
    {
        // do something with data_
    }
private:
    using boc = boost::container;

    constexpr std::size_t preset_capacity_ = 400;
    boc::small_vector<int, preset_capacity_> data_;
}

您应该分析一下这是否真的更好,并注意这可能会使用更多内存,如果有很多 Test 个实例,这可能是一个问题。