牵着老婆满街逛

严以律己,宽以待人. 三思而后行.
GMail/GTalk: yanglinbo#google.com;
MSN/Email: tx7do#yahoo.com.cn;
QQ: 3 0 3 3 9 6 9 2 0 .

boost之array,效率与优雅之正交点

转载自:http://caobeixingqiu.is-programmer.com/posts/6326.html

    如果你是STL的惯用者,且对效率持有莫大的兴趣,你可能会对原生数组而不能优雅的与 STL 算法结合而感到不满和懊恼,你充其量可以这样使用:


int nArray[4] = {1,2,3,4};
const int Len = sizeof( nArray ) / sizeof( int );
int nCount = std::count( nArray, nArray + Len, 3 );
 


   然而你不肯运用其他如 swap 等算法,数组是一个小型集合, 不能直接赋值。可能在模板中你更渴望有直接赋值的要求:


int nArray[4] = {1,2,3,4};
int nArray2[4] = nArray;        // 这种优雅的语法实在比 memcpy 等更具有观赏性
std::swap( nArray, nArray2 );   // 适应这种算法也更通用
 


   幸而,boost提供了这样一个物件: array, 说到底,array 只是原生数组的浅薄包装而已,你甚至可以像原生数组那样直接以大括号形式的赋值方式赋值:


array <int, 2> array = {{1,2}};
array <int, 2> array = {1,2};   // 显然大部分编译器已经支持一个大括号的初始化了
 

   这种赋值方式的技术要求是:
        1. 不允许有用户定义的构造函数( 可以有析构 )
        2. 不允许有 private 和 protected 的数据成员 ( 可以有 static 成员 )
        3. 不允许有 父类
        4. 无虚函数
   从 C++ 对象模型角度来说,其结构在内存中是连续的一段,没有额外的其他东西如虚表指针.

   下面是其简单定义:
 

    template<class T, std::size_t N>
    class array {
      public:
        T elems[N];    // 被包装之原生数组

      public:
        // 类型定义
        typedef T              value_type;
        typedef T*             iterator;
        typedef const T*       const_iterator;
        typedef T&             reference;
        typedef const T&       const_reference;
        typedef std::size_t    size_type;
        typedef std::ptrdiff_t difference_type;

        // 迭代器支持
        iterator begin() { return elems; }
        iterator end() { return elems+N; }

        // 反向迭代器支持
        typedef std::reverse_iterator<iterator> reverse_iterator;
        typedef std::reverse_iterator<const_iterator> const_reverse_iterator;

        reverse_iterator rbegin() { return reverse_iterator(end())}
        reverse_iterator rend() { return reverse_iterator(begin())}

        // 操作符[]
        reference operator[](size_type i) 
        { 
            BOOST_ASSERT( i < N && "out of range" )
            return elems[i];
        }
        
        // 带有检查的 at() 
        reference at(size_type i) { rangecheck(i)return elems[i]}
        const_reference at(size_type i) const { rangecheck(i)return elems[i]}
    
        // front() 和 back()
        reference front() 
        { 
            return elems[0]
        }
        
        reference back() 
        { 
            return elems[N-1]
        }
        
        // 大小为常量, 提供了 enum 来支持模板编程
        static size_type size() { return N; }
        static bool empty() { return false}
        static size_type max_size() { return N; }
        enum { static_size = N };

        // swap (线性复杂度)
        void swap (array<T,N>& y) {
            std::swap_ranges(begin(),end(),y.begin());
        }

        // direct access to data (read-only)
        const T* data() const { return elems; }
        T* data() { return elems; }

        // use array as C array (direct read/write access to data)
        T* c_array() { return elems; }

        // 允许类型转换的赋值
        template <typename T2>
        array<T,N>& operator= (const array<T2,N>& rhs) {
            std::copy(rhs.begin(),rhs.end(), begin());
            return *this;
        }

        // 数组填充某一值
        void assign (const T& value)
        {
            std::fill_n(begin(),size(),value);
        }

        //  检测区间
        static void rangecheck (size_type i) {
            if (i >= size()) {
                throw std::out_of_range("array<>: index out of range");
            }
        }

    };
 


    当 N = 0 时, 像elem[0]这样的语法是错误的,故以偏特化。内部去掉了 T elems[N]; 大部分接口只是为了统一,内部并未实作,顶多是抛出异常。

    另外,一些有用的协助函数,主要是比较函数: ==, <, !=, >, <=, >=. 还有一个全局的swap,内部主要调用array内部的swap实现:

    // swap()
    template<class T, std::size_t N>
    inline void swap (array<T,N>& x, array<T,N>& y) {
        x.swap(y);
    }

  

瑕疵:

不过,我们只有显示的提供给数组一个大小,不能再像下面一样使用编译器来替我们工作了:

int arr[] = {1,2,3,4,5};

而只有这样:

array<int, 5> arr = {1,2,3,4,5};

另外,像   char 这样的特殊元素, 我们就不免小心(见下篇)。

不过,比起array之功,这点瑕疵也完全可以忽略。

posted on 2010-10-13 12:10 杨粼波 阅读(797) 评论(0)  编辑 收藏 引用


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理