std::begin 是空的 std::valarray 未定义行为吗?

Is std::begin on an empty std::valarray undefined behavior?

我在玩 std::valarray 和 UndefinedBehaviorSanitizer,并注意到 std::begin 一个空的 std::valarray 会导致未定义的行为。这是代码:

#include <valarray>

int main() {
    std::valarray<int> a;
    std::begin(a);
}

要重现,请使用 g++ -fsanitize=undefined 编译代码并 运行 结果可执行文件。

这是 libstdc++std::begin 实现。

template<class _Tp>
  inline _Tp*
  begin(valarray<_Tp>& __va)
  { return std::__addressof(__va[0]); }

似乎 _val[0] 为空 std::valarray 创建了一个空值引用,这导致了未定义的行为。

这是 libstdc++ 的错误吗?

n4659 - C++17 final working draft

§26.2.1 General container requirements [container.requirements.general]

Table 83 — Container requirements

a.begin() - no precondition

所以 a.begin() 必须在空容器上有效。

但是 valarray 是在 §29.7 数值数组 [numarray] 中定义的 §29 数值库 [numerics]章节,所以它不是容器库章节的直接部分。

std::begin(valarray)§29.7.10 valarray range access [valarray.range]中定义,这里没有提到前提条件。最相关的名言是:

§ 29.7.10 valarray range access [valarray.range]

  1. The iterators returned by begin and end for an array are guaranteed to be valid until the member function resize(size_t, T) (29.7.2.8) is called for that array or until the lifetime of that array ends, whichever happens first.

     template <class T> unspecified 1 begin(valarray<T>& v);
     template <class T> unspecified 2 begin(const valarray<T>& v);
    
  2. Returns: An iterator referencing the first value in the array.

所以问题是 Table 83 是否适用于此。 valarray§29.7.2 Class template valarray [template.valarray] 中描述并且标准说:

29.7.2.1 Class template valarray overview [template.valarray.overview]

  1. The class template valarray is a one-dimensional smart array,

在我看来这意味着 valarray 是属于 §26.2.1 一般容器要求

的容器

对我来说,空 valarray 上的 std::begin 应该是有效的。另一方面,“Returns:引用数组中第一个值的迭代器”可能暗示一个先决条件,即 valarray 不能为空。所以我唯一的结论是,标准在这方面应该更加明确。