考虑以下代码片段,这是C ++ 11编译器完全可以接受的:
#include <array>
#include <iostream>
auto main() -> int {
std::array<double, 0> A;
for(auto i : A) std::cout << i << std::endl;
return 0;
}
根据标准§23.3.2.8[零大小的数组]:
1
数组应为特殊情况N == 0
提供支持。
2
如果是N == 0
,begin() == end() ==
唯一值。
的返回值data()
未明确。
3
为零大小的数组调用front()
或back()
的效果未定。
4
成员函数swap()
应该有一个noexcept-speci fi cation,相当于noexcept(true)
。
如上所示,零大小的std::array
在C ++ 11中是完全允许的,与零大小的数组(例如,int A[0];
)相比,它们是明确被禁止的,但它们是允许的一些编译器(例如,GCC)的未定义行为的代价。
考虑到这种“矛盾”,我有以下问题:
为什么C ++委员会决定允许零大小的std::array
?
有什么有价值的用途吗?
答案 0 :(得分:43)
如果你有一个泛型函数,那么如果该函数随机中断特殊参数就不好了。例如,假设您可以使用模板函数将N
个随机元素形成一个向量:
template<typename T, size_t N>
std::array<T, N> choose(const std::vector<T> &v) {
...
}
如果N
由于某种原因结果为零,则会导致未定义的行为或编译器错误,从而无法获得任何结果。
对于原始数组,限制背后的原因是你不希望类型为sizeof T == 0
,这会导致与指针算法结合的奇怪效果。如果你没有为它添加任何特殊规则,那么零元素的数组的大小为零。
但std::array<>
是一个类,类的大小总是&gt; 0.因此,您不会遇到std::array<>
的问题,并且最好不使用模板参数的任意限制。
答案 1 :(得分:4)
我能想到的一个用途是可以返回零长度数组,并具有特定的功能。
例如,请参阅std::array
函数empty()
上的文档。它具有以下返回值:
true if the array size is 0, false otherwise.
http://www.cplusplus.com/reference/array/array/empty/
我认为返回和检查0长度数组的能力符合stl类型的其他实现的标准,例如。矢量和地图因此很有用。
答案 2 :(得分:1)
与其他容器类一样,能够拥有一个表示事物数组的对象并使该数组成为空或变为空是很有用的。如果那是不可能的,那么就需要创建另一个对象或管理类来以合法的方式表示该状态。拥有该功能已包含在所有容器类中,非常有用。在使用它时,人们只需要习惯将数组作为一个可能为空的容器,并在引用它的成员之前检查大小或索引,以防它可能没有指向任何东西。 / p>
答案 3 :(得分:1)
实际上有很多情况下你希望能够做到这一点。它也出现在很多其他语言中。例如,Java实际上有Collections.emptyList()
,它返回的列表不仅大小为零,而且无法扩展,调整大小或修改。
示例用法可能是您有一个代表公共汽车的班级和该班级内的乘客列表。该列表可能是懒惰的初始化,仅在乘客登机时创建。如果有人调用getPassengers()
,则可以返回一个空列表,而不是每次只报告空列表时创建一个新列表。
返回null也可以用于类的内部效率 - 但是对于每个使用该类的人来说,生活会变得更加复杂,因为无论何时调用getPassengers()
,您都需要对结果进行null检查。相反,如果你得到一个空列表,那么只要你的代码没有假设列表不为空,你就不需要任何特殊代码来处理它为空。