• STL源码阅读(九)


    STL源码阅读(九)(SGI STL v3.3)

    limits (<limits>)

    提供编译时算术类型变量的属性信息。

    valarray (<valarray>)

    数值数组类

    // valarray的元素选择类
    class slice {
     ...
    private:
      size_t _M_start;  // 起始元素的位置 
      size_t _M_length; // 元素的个数
      size_t _M_stride; // 元素之间的步长
     ...
    }
    // slice作为角标号的帮助类
    template <class _Tp>
    class slice_array {
      friend class valarray<_Tp>;
    public:
      typedef _Tp value_type;
     ...
      slice          _M_slice;  // 下标
      valarray<_Tp>& _M_array;  // 数值数组
     ...
    
    // 定义了=、*=、/=、%=、+=、-=、^=、&=、|=、<<=、>>=,算术、逻辑与移位操作
    // 操作都是在指定的角标处的元素上进行运算的,看一小段源码即可明白
    void operator=(const valarray<value_type>& __x) const {
        size_t __index = _M_slice.start();
        for (size_t __i = 0;
             __i < _M_slice.size();
             ++__i, __index += _M_slice.stride()) // 对于赋值数组__x是以1为角标步长的
          _M_array[__index] = __x[__i];
    }
    }
    // valarray的元素选择类,可以选择多组(形成多维数组)
    class gslice {
    private:
      size_t _M_start;  // 起始元素下标
      valarray<size_t> _M_lengths;  // 每一维的元素个数
      valarray<size_t> _M_strides;  // 定义每一维元素之间的步长
     ...
    }
    template <class _Tp>
    class gslice_array {
      friend class valarray<_Tp>;
    public:
      typedef _Tp value_type;
     ...
      gslice                _M_gslice;  // 下标
      valarray<value_type>& _M_array;   // 数值数组
     ...
    }
    
    // 所定义的操作符类似于slice_array,只不过前者是多维的
    // 在有效的下标处进行操作
    template <class _Tp>
    class mask_array {
      friend class valarray<_Tp>;
    public:
      typedef _Tp value_type;
     ...
      valarray<bool> _M_mask;
      valarray<_Tp>& _M_array;
     ...
    }
    // 在指定的一些下标处进行操作
    template <class _Tp>
    class indirect_array {
      friend class valarray<_Tp>;
    public:
      typedef _Tp value_type;
     ...
      valarray<size_t> _M_addr;
      valarray<_Tp>&   _M_array;
     ...
    }
    // valarray基类
    template <class _Tp> 
    struct _Valarray_base {
     ...
        _Tp*   _M_first;    // 指向数组的指针,分配的是一段连续内存
        size_t _M_size;     // 数组大小
     ...
        // 使用malloc和free来分配、释放内存
    }
    
    template <class _Tp> 
    class valarray : private _Valarray_base<_Tp> {
     ...
      friend class gslice;
    
    public:
        typedef _Tp value_type;
        // 注意标量赋值是将所有元素赋为同一个值
       valarray& operator=(const value_type& __x) {
         fill_n(this->_M_first, this->_M_size, __x);
         return *this;
       }
    
        // 注意resize会先释放原内存,然后再分配__n*sizeof(value_type)
        // 大小的内存,并以__x初始化每个元素
      void resize(size_t __n, value_type __x = value_type()) {
        destroy(this->_M_first, this->_M_first + this->_M_size);
        this->_Valarray_base<_Tp>::_M_deallocate();
        this->_Valarray_base<_Tp>::_M_allocate(__n);
        uninitialized_fill_n(this->_M_first, this->_M_size, __x);
      }
     ...
    }
    
    // 注意operator*是按照对应元素相乘的,不是向量乘。其它算术操作同理
    template <class _Tp> inline valarray<_Tp> operator*(const valarray<_Tp>& __x,
                                   const valarray<_Tp>& __y) {
      typedef typename valarray<_Tp>::_NoInit _NoInit;
      valarray<_Tp> __tmp(__x.size(), _NoInit());
      for (size_t __i = 0; __i < __x.size(); ++__i)
        __tmp[__i] = __x[__i] * __y[__i];
      return __tmp;
    }
    
    // 返回一个新的数值数组,它的元素是原数组平移n(正值向左,负值向右)后的元素的副本
    template <class _Tp>
    valarray<_Tp> valarray<_Tp>::shift(int __n) const
    {
      valarray<_Tp> __tmp(this->size());
    
      if (__n >= 0) {
        if (__n < this->size())
          copy(this->_M_first + __n, this->_M_first + this->size(),
               __tmp._M_first);
      }
      else {
        if (-__n < this->size())
          copy(this->_M_first, this->_M_first + this->size() + __n,
               __tmp._M_first - __n);
      }
      return __tmp;
    }
    
    // 循环平移数组元素
    template <class _Tp>
    valarray<_Tp> valarray<_Tp>::cshift(int __m) const
    {
      valarray<_Tp> __tmp(this->size());
    
      // Reduce __m to an equivalent number in the range [0, size()).  We
      // have to be careful with negative numbers, since the sign of a % b
      // is unspecified when a < 0.
      long __n = __m;
      if (this->size() < numeric_limits<long>::max())
        __n %= long(this->size());
      if (__n < 0)
        __n += this->size();
    
      copy(this->_M_first,       this->_M_first + __n,
           __tmp._M_first + (this->size() - __n));
      copy(this->_M_first + __n, this->_M_first + this->size(),
           __tmp._M_first);
    
      return __tmp;
    }

    参考资料

    1. sgi STL
    2. cppreference.com
  • 相关阅读:
    tomcat配置
    java.net.ConnectException: Connection timed out: connect,java.net.ConnectException: Connection timed out: connect at java.net.DualStackPlainSocketImpl.waitForConnect
    Tomat 下载地址
    Gradle的依赖方式——Lombok在Gradle中的正确配置姿势 本文来源:码农网 本文链接:https://www.codercto.com/a/70161.html
    mssql 那表语句
    监控系统搭建
    vue 子组件触发父组件方法的两种方式
    css margin边界叠加问题详谈
    sticky footer
    JS的构造函数
  • 原文地址:https://www.cnblogs.com/corfox/p/6063300.html
Copyright © 2020-2023  润新知