glibcxx STL在其std :: valarray :: sum()的实现中是否不正确? [英] Is the glibcxx STL incorrect in its implementation of std::valarray::sum()?

查看:87
本文介绍了glibcxx STL在其std :: valarray :: sum()的实现中是否不正确?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当我碰到某些东西时,我在玩 valarrays 我的编译器的STL实现.这是我可以产生的最小示例:

I was toying with valarrays when I hit something I consider a bug in my compiler's STL implementation. Here is the smallest example I could produce:

#include <iostream>
#include <string>
#include <vector>
#include <iomanip>
#include <valarray>

using namespace std;

int main()
{
    valarray<int> Y(0xf00d, 1);
    valarray<valarray<int>> X(Y, 1);
    cout << "Y[0]           = " << std::hex << Y[0]       << '\n';
    cout << "X[0][0]        = " << std::hex << X[0][0]    << '\n';
    cout << "X[0].size()    = " << X[0].size()            << '\n';
    cout << "X.sum().size() = " << X.sum().size()         << '\n';
}

这将输出:

$ g++ -std=c++17 -O2 -Wall -pedantic -pthread main.cpp && ./a.out
Y[0]           = f00d
X[0][0]        = f00d
X[0].size()    = 1
X.sum().size() = 0

您可以在 coliru

为什么我认为这是一个错误?因为按照标准(26.6.2.8)

Why do I consider this a bug ? Because according to the standard (26.6.2.8)

T sum()const;

此功能只能在类型为T的情况下实例化 可以应用哪个运算符+ =.此函数返回所有的总和 数组的元素.如果数组的长度为0,则行为 未定义.如果数组的长度为1,sum()返回的值为 元素0.否则,返回值通过应用 运算符+ =到数组元素和所有其他元素的副本 数组的顺序不确定.

This function may only be instantiated for a type T to which operator+= can be applied. This function returns the sum of all the elements of the array. If the array has length 0, the behavior is undefined. If the array has length 1, sum() returns the value of element 0. Otherwise, the returned value is calculated by applying operator+= to a copy of an element of the array and all other elements of the array in an unspecified order.

valarray确实具有 + =运算符

valarray does have a += operator

所以我希望X.sum()具有与X[0]相同的值.但这显然不是事实,因为它的大小是0而不是1.

So I would expect X.sum() to have the same value than X[0]. But it is clearly not the case, because its size is 0 instead of 1.

我查看了sum()的实现,并将其追溯到这段代码:

I looked in the implementation of sum() and tracked it back to this piece of code:

  //
  // Compute the sum of elements in range [__f, __l)
  // This is a naive algorithm.  It suffers from cancelling.
  // In the future try to specialize
  // for _Tp = float, double, long double using a more accurate
  // algorithm.
  //
  template<typename _Tp>
    inline _Tp
    __valarray_sum(const _Tp* __f, const _Tp* __l)
    {
      _Tp __r = _Tp();
      while (__f != __l)
        __r += *__f++;
      return __r;
    }

我们了解问题的根源.该代码将和累加到__r中,但是默认情况下,它不是用valarray中的第一项初始化__r. valarray的默认构造函数创建一个大小为0的数组.因此最终结果仍然是大小为0的valarray.

And we understand where the problem comes from. The code accumulates the sum into __r, but instead of initializing __r with the first item in the valarray, it is default constructed. The default constructor for valarray creates an array of size 0. And so the final result is still a valarray of size 0.

我对标准的理解是否有效(并且glibcxx STL有一个错误)?还是应该纠正我?

Is my understanding of the standard valid (and glibcxx STL has a bug)? Or should I be corrected?

出于记录,我在cygwin下使用的是g ++ 7.3.0,但它是在coliru上复制的,它可能不在cygwin下运行...

For the record, I am using g++ 7.3.0 under cygwin, but it is reproduced on coliru which probably isn't running under cygwin...

推荐答案

这对我来说是个错误. sum()

This is a bug to me. sum()

要求: size() > 0.只能为可应用operator+=的类型T实例化此功能.

Requires: size() > 0. This function may only be instantiated for a type T to which operator+= can be applied.

valarray确实具有operator +=,因此符合条件.它是 operator +=

and valarray does have a operator += so it qualifies. It's operator +=

要求: size() == v.size().如果指示的运算符可以应用于类型T的两个操作数,则只能为类型T实例化这些运算符中的每一个.valarray复合赋值运算符左侧的元素值不依赖于T的值.左侧的另一个元素.

Requires: size() == v.size(). Each of these operators may only be instantiated for a type T if the indicated operator can be applied to two operands of type T. The value of an element in the left-hand side of a valarray compound assignment operator does not depend on the value of another element in that left hand side.

因此,通过执行_Tp __r = _Tp();,它们会生成一个valarray,其size()与元素的大小不相等,因此无法与operator +=一起使用.

So by doing _Tp __r = _Tp(); they generate a valarray whose size() does not equal the size of the elements thus it isn't usable with it's operator +=. A more correct implementation would be

  template<typename _Tp>
    inline _Tp
    __valarray_sum(const _Tp* __f, const _Tp* __l)
    {
      _Tp __r = *__f++; // this is okay as the function is requires size > 0.  It is the users responsibility to make sure that is the case
      while (__f != __l)
        __r += *__f++;
      return __r;
    }

这篇关于glibcxx STL在其std :: valarray :: sum()的实现中是否不正确?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆