在 C++ 中,如果必须在编译时确定大小,std::array 的意义何在?

In C++ what is the point of std::array if the size has to be determined at compile time?

请原谅我的无知,在我看来 std::array 应该是常规数组的 STL 替代品。但是因为数组大小必须作为模板参数传递,所以它阻止我们创建大小仅在运行时已知的 std::array

std::array<char,3> nums {1,2,3}; // Works.

constexpr size_t size = 3;
std::array<char,size> nums {1,2,3}; // Works.

const buf_size = GetSize();
std::array<char, buf_size> nums; // Doesn't work.

我假设 C++ 中数组的一个非常重要的用例是基于运行时输入创建固定大小的数据结构(比如为读取文件分配缓冲区)。

我使用的解决方法是:

// Create a array pointer for on-the-spot usecases like reading from a file.
char *data = new char[size];
...
delete[] data;

或:

// Use unique_ptr as a class member and I don't want to manage the memory myself.
std::unique_ptr<char[]> myarr_ = std::unique_ptr<char[]>(new char[size]);

如果我不关心固定尺寸,我知道我可以使用 std::vector<char> 和预定义尺寸如下:

std::vector<char> my_buf (buf_size);

为什么 std::array 的设计者选择忽略这个用例?也许我不明白 std::array.

的真正用例

编辑:我想另一种表达我的问题的方式也可能是——为什么设计者选择将大小作为模板参数而不是构造函数参数传递?选择后者是否会导致难以提供 std::array 目前拥有的功能?对我来说,这似乎是一种深思熟虑的设计选择,我不明白为什么。

std::array 是 C 风格数组的替代品。

C++ 标准不允许在没有编译时定义大小的情况下声明 C 样式数组。

易于编程

std::array 促进了 std::vector 中使用的几个有益的界面和习语。对于普通的 C 风格数组,不能有 .size()(没有 sizeof hack)、.at()(超出范围的异常)、front()/back()、迭代器等。一切都必须手工编码。

许多程序员可能会选择 std::vector 即使对于编译时已知大小的数组,只是因为他们想利用上述编程方法。但这夺走了编译时固定大小数组的性能。
因此,std::array 是由库制造商提供的,以阻止 C 风格的数组,并且在编译时已知大小时避免 std::vectors。

我理解的两个主要原因是:

  • std::array 实现 STL 的集合类型接口,允许将 std::array 按原样传递给接受任何 STL 迭代器的函数和方法。
  • 防止数组指针衰减...(下)

...这是跨 function/method 边界保留类型信息,因为它防止 Array Pointer Decay.

给定一个裸数组C/C++,你可以通过4种方式将它作为参数传递给另一个函数:

void by_value1   ( const T* array )
void by_value2   ( const T array[] )
void by_pointer  ( const T (*array)[U] )
void by_reference( const T (&array)[U] )
  • by_value1by_value2 在语义上是相同的并且会导致指针衰减,因为接收函数不知道 sizeof 数组。
  • by_pointerby_reference 都要求 U 通过已知的编译时常量,但保留 sizeof 信息。

因此,如果您通过使用 by_pointerby_reference 避免数组衰减,您现在每次更改数组大小时都会遇到维护问题,您必须手动更新所有调用站点在 U.

中具有该尺寸

通过使用 std::array 可以为您处理这些函数 template 函数,其中 U 是参数(当然,您可以 still 使用 by_pointerby_reference 技术,但语法更混乱)。

...所以 std::array adds a 5th way:

template<typename T, size_t N>
void by_stdarray( const std::array<T,N>& array )