可变长度std::类似数组

Variable-length std::array like

本文关键字:数组 std      更新时间:2023-10-16

由于我通常使用的C++编译器允许可变长度的数组(例如,取决于运行时大小的数组),我想知道是否有类似std::array的可变大小的东西?当然,std::vector的大小是可变的,但它在堆上进行分配,并在需要时进行重新分配。

我喜欢在运行时定义一个大小为堆栈分配的数组。是否有任何std-模板可能具有此功能?也许使用具有固定最大大小的std::vector

目前有两个建议正在制定中,以将运行时固定大小的数组引入C++,这可能会引起您的兴趣:

  • 具有自动存储持续时间的运行时大小的阵列。这将使运行时大小的数组成为一种语言特性(类似于C11)。所以你可以做:

    void foo(std::size_t size) {
    int arr[size];
    }
    
  • C++动态数组。这将为库带来一个新的容器std::dynarray,该容器在构建时具有固定的大小。它旨在进行优化,以便在可能的情况下在堆栈上进行分配。

    void foo(std::size_t size) {
    std::dynarray<int> arr(size);
    }
    

这两个都是作为阵列扩展技术规范的一部分进行的,该技术规范将与C++14一起发布。

更新:std::dyarray尚未实现(2021年8月25日)。请参阅dyarrays的状态如何?

正如Daniel在注释中所说,std::array的大小被指定为模板参数,因此在运行时无法设置。

您可以通过构造函数参数传递最小容量来构造std::vector

#include <vector>
int main(int argc, char * argv[])
{
std::vector<int> a;
a.reserve(5);
std::cout << a.capacity() << "n";
std::cout << a.size();
getchar();
}

但是Still矢量的内容将存储在堆中,而不是堆栈中。问题是,编译器必须知道在函数执行之前应该为其分配多少空间,因此根本不可能在堆栈上存储可变长度的数据。

也许使用具有固定最大大小的std::vector

如果允许升压,那么boost::container::static_vectorboost::container::small_vector是我能想到的最接近的

boost::container::static_vector<int, 1024> my_array;
boost::container::small_vector<int, 1024> my_vector;

static_vector是一个类似于boost::container::vector的序列容器,具有可以改变大小的连续存储,以及boost::array的静态分配、低开销和固定容量。

每个对象的大小仍然是固定的,但如果分配数量很大和/或项目计数很小,则这是值得的

如果矢量可以增长超过极限,那么只需使用boost::container::small_vector。只有当大小大于定义的限制时,才会触摸堆

small_vector是一个类似向量的容器,针对包含很少元素的情况进行了优化。它包含一些预先分配的元素,当元素的实际数量低于预先分配的阈值时,可以避免使用动态存储分配。


如果您使用Qt,则QVarLengthArray是另一种方法:

QVarLengthArray就是试图在C++语言中解决这一差距。它在堆栈上分配一定数量的元素,如果将数组调整为更大的大小,它会自动使用堆。堆栈分配的优点是它比堆分配快得多。

示例:

int myfunc(int n)
{
QVarLengthArray<int, 1024> array(n + 1);
...
return array[n];
}

其他一些类似的解决方案:

  • llvm::SmallVector
  • Facebook的folly::small_vector
  • 电子艺术标准模板库的eastl::fixed_vector

如果不允许3rd方解决方案,那么您可以通过将std::array封装在结构中来滚动自己的解决方案,以获得静态向量

template<typename T, size_t N> 
struct my_static_vector
{
explicit static_vector(size_t size) { } // ...
size_t size() const noexcept { return curr_size; }
static size_t capacity() const noexcept { return N; }
T& operator[](size_t pos) { return data[pos]; }
void push_back(const T& value) { data[curr_size++] = value; }
// ...
private:
std::array<typename T, N> data;
std::size_t curr_size;
}

如果需要small_vector,则可以使用std::variant同时包含my_static_vector和矢量

template<typename T, size_t N> 
struct my_small_vector
{
explicit small_vector(size_t size) { } // ...
size_t size() const noexcept {
if (data.index() == 0) {
return data.get<0>().size();
} else {
return data.get<1>().size();
}
}
static size_t capacity() const noexcept {
if (data.index() == 0) {
return data.get<0>().capacity();
} else {
return data.get<1>().capacity();
}
}
// ...
private:
std::variant<my_static_vector<T, N>, std::vector<T>> data;
}