为什么 std::array 中没有 operator->

Why there is no operator-> in std::array

我正在写一个 std::array class 作为一个小练习,期间我发现 std::array 没有实现 operator->。 因此,对于数组,允许以下内容

struct S { int s; };
S c[2];
c->s = 2;

但对于 std::array 这是不可能的

struct S { int s; };
std::array<S,2> cpp;
// cpp->s = 2;  // does not compile

这使得 std::array 与 C 数组不完全兼容。 这个决定有什么原因吗?


(我预料到会有严厉的反应,但我很惊讶他们来得这么快。)

显然,正如我们所知,数组不是指针,而是指向它们的衰减。 C++ 中的问题不在于它们衰减,而是它们自动衰减。如果有人故意将 -> 语法用于 std::array,这很可能是糟糕的设计,但不是问题。

即使使用 operator->std::array 也类似于 C++ 中的第一个 class-citizien(不是数组)。

C++ 不是一种可以防止用户受到任何伤害的语言。

Why there is no operator-> in std::array

因为数组不是间接形式,数组也没有成员,所以提供间接成员访问运算符意义不大。

将 operator-> 与数组一起使用非常具有误导性(在我看来),它仅作为数组到指针衰减的副作用起作用。首先使用 std::array 的约 50% 的原因是为了避免无意的数组到指针衰减。

c->s 之所以有效,是因为像 c[2] 这样的原始数组会自动 衰减 到表达式中的指针。

所以 c->s 等价于 c[0].s.

诸如 std::array 之类的对象不会衰减为指针并且不提供 ->T* 重载,因此 cpp->s 不起作用。


std::array [is] not fully compatible to a C-array

幸运的是没有!它是一个类似数组的 object,解决了许多与原始数组相关的问题。

c->s这样访问数组的第一个元素可能简洁明了,但它的可读性值得怀疑,事实上很多人认为数组衰减是一个问题而不是一个特性。

CppCoreGuidelines admits array-to-pointer-decay 也是一个问题领域:

Ideally, a program would be completely statically (compile-time) type safe. Unfortunately, that is not possible. Problem areas:

  • unions
  • casts
  • array decay
  • range errors
  • narrowing conversions

std::array 通过禁止它来解决源于 C 的特质。

C++ is not a language where the user shall be prevented from every harm ...

没错。正如他们所说,“当你的锤子是 C++ 时,一切都变成拇指”。 但这并不意味着我们对此无能为力,一次解决一个问题领域。这就是 std::array 对原始数组的作用,std::unique_ptr 对拥有指针的作用,nullptrNULL 的作用,等等

你可能想说

c->s = 2;

而不是 c->x。当 c 声明为数组时,变量 c 只是指向该数组的第一个元素 c[0] 的指针,在您的例子中是一个结构。将运算符 -> 应用于该指针 c->sc[0].s 相同。 使用 std::array 时,变量 cpp 不代表指向第一个元素的指针。因此箭头运算符在这里没有任何意义。