首页 > 解决方案 > std::begin 是空的 std::valarray 未定义行为吗?

问题描述

我在玩std::valarrayUndefinedBehaviorSanitizer,并注意到std::beginstd::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]为空 s 创建了一个空值引用,std::valarray这会导致未定义的行为。

这是来自 libstdc++ 的错误吗?

标签: c++undefined-behaviorlibstdc++valarray

解决方案


n4659 - C++17 最终工作草案

§26.2.1 一般容器要求 [container.requirements.general]

表 83——容器要求

a.begin()- 没有先决条件

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

但是在§29 Numerics library [numerics]章节的§29.7 Numeric arrays [numarray]valarray中定义,因此它不是容器库章节的直接部分。

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

§ 29.7.10 valarray 范围访问 [valarray.range]

  1. begin数组返回的和end为数组返回的迭代器保证有效,直到resize(size_t, T) 为该数组调用成员函数 (29.7.2.8) 或直到该数组的生命周期结束,以先发生者为准。

     template <class T> unspecified 1 begin(valarray<T>& v);
     template <class T> unspecified 2 begin(const valarray<T>& v);
    
  2. 返回: 引用数组中第一个值的迭代器。

所以问题是表 83 是否适用于此。valarray§29.7.2 类模板 valarray [template.valarray]中有描述,标准说:

29.7.2.1 类模板 valarray 概述 [template.valarray.overview]

  1. 类模板 valarray 是一个一维智能数组,

在我看来,这valarray是一个符合§26.2.1 一般容器要求的容器

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


推荐阅读