47

考虑以下一段代码,它完全可以被 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 == 0begin() == end() ==独特的价值。的返回值
data()未指定。

3调用front()back()对零大小数组的影响是未定义的。

4成员函数swap()应该有一个 noexcept 规范,它等价于 noexcept(true).

如上所示,零大小std::array的 s 在 C++11 中是完全允许的,与零大小的数组(例如,int A[0];)相反,它们被明确禁止,但某些编译器(例如,GCC)以未定义行为为代价允许它们.

考虑到这种“矛盾”,我有以下问题:

  • 为什么 C++ 委员会决定允许零大小std::array的 s?

  • 有什么有价值的用途吗?

4

4 回答 4

45

如果您有一个通用函数,那么如果该函数随机中断特殊参数,那就不好了。例如,假设您可以有一个模板函数,它将N随机元素形成一个向量:

template<typename T, size_t N>
std::array<T, N> choose(const std::vector<T> &v) {
   ...
}

如果这导致未定义的行为或编译器错误,如果N由于某种原因结果为零,则什么也得不到。

对于原始数组,限制背后的一个原因是您不希望类型带有sizeof T == 0,这会导致与指针运算相结合的奇怪效果。如果您不为其添加任何特殊规则,则具有零元素的数组的大小为零。

Butstd::array<>是一个类,并且类的大小总是 > 0。所以你不会遇到这些问题std::array<>,并且没有模板参数的任意限制的一致接口是可取的。

于 2014-06-10T23:47:37.393 回答
4

我能想到的一种用途是返回零长度数组是可能的,并且具有需要专门检查的功能。

例如,请参阅有关std::array功能的文档empty()。它具有以下返回值:

true if the array size is 0, false otherwise.

http://www.cplusplus.com/reference/array/array/empty/

我认为返回和检查长度为 0 的数组的能力符合 stl 类型的其他实现的标准,例如。矢量和地图,因此很有用。

于 2014-06-10T23:46:41.190 回答
1

As with other container classes, it is useful to be able to have an object that represents an array of things, and to have it possible for that array to be or become empty. If that were not possible, then one would need to create another object, or a managing class, to represent that state in a legal way. Having that ability already contained in all container classes, is very helpful. In using it, one then just needs to be in the habit of relating to the array as a container that might be empty, and checking the size or index before referring to a member of it in cases where it might not point to anything.

于 2014-06-11T06:47:59.850 回答
1

实际上有很多情况下您希望能够做到这一点。它也出现在许多其他语言中。例如,Java 实际上有Collections.emptyList()它返回一个列表,该列表不仅大小为零,而且不能扩展、调整大小或修改。

一个示例用法可能是,如果您有一个代表公共汽车的类和该类中的乘客列表。该列表可能是惰性初始化的,仅在乘客登机时创建。如果有人打电话getPassengers(),那么可以返回一个空列表,而不是每次都创建一个新列表来报告为空。

返回 null 也可以提高类的内部效率 - 但会使使用该类的每个人的生活变得更加复杂,因为每当您调用时,getPassengers()您都需要对结果进行 null 检查。相反,如果您得到一个空列表,那么只要您的代码不假设列表不为空,您就不需要任何特殊代码来处理它为空。

于 2014-06-11T08:23:35.770 回答