一组新的多维数组模板类
by chen3feng(RoachCock@smth)
email: chen3feng@163.com, chen3fengx@163.com, chen3fengx@hotmail.com
[引言]
在C/C++开发中,多维数组是一个让很多人感到棘手的问题.原因是C/C++中,多维数组被看
作是数组的数组.
在向函数传递参数的时候,多维数组经常让人感到是麻烦的制造者,通常都是传递首地址
和每一维的大小:
void foo(int *,int ,int);;
int a[10][10];;
foo(&a[0][0],10,10);;
//...
十分的麻烦,在函数中访问时也得自己用乘法来计算元素的位置,更是十分麻烦.
C99标准推出了可变大小的多维数组,当然,实现该标准的编译器还不多,但是也从一个方
面说明了变量大小的多维数组是很有用的.
C++标准直到现在还不支持,明年(2003年)的新标准也不知道会不会加进去.但是C++程序
员自己有办法,利用C++的模板,运算符重载等技巧,完全可以构建出方便实用的多维数组类
我抢在明年之前做出这组模板类,也希望即使新标准增加了变量大小的多维数组,我的工
作也仍有一些意义, :)
另外,多维数组的空间是连续的,这跟用vector of vector实现的不一样,可以用迭代器
从头到脚挨个摸一遍.
boost库也提供了多维数组类,当然还有别的几个数组类.我感觉boost多维数组类的缺点
就是只支持动态数组,对静态和动态数组没有一个统一的非GP的接口,因此我着重于这方
面的改进,
[简介]
该组类有以下几个类模板组成
1.
template <;typename T, size_t DimNum>;
class array_base;;
该类是其他几个数组类的基类 // 由于编译器对C++标准实现参差不齐的原因,该类实际
上不是根类,不过应用中不需要知道这一点.
提供了基本的功能,比如[]运算符,迭代器的类型声明,迭代器的获取,value_type等的定
义等
等
2.
template <;typename T, size_t d1, size_t d2 = -1, size_t d3 = -1>;
class static_array;;
静态的数组类,从array_base派生而来,因此除了兼容也是由array_base派生出来的其他
类外,还有自己的特点,就是提供了一个elements的public成员,直接暴露给用户,访问
速度可以很快.
3.
template<;typename T,size_t DimNum, typename A=std::allocator<;T>; >;
class dynamic_array;; //:public array_base<;T, DimNum>;
看得出也是从array_base派生的,另外,他是可以resize的.还支持reserve等STL容器的操
作.
4.
template <;typename T, size_t DimNum, typename A=std::allocator<;T>; >;
class shared_array;; //: public array_base<;T, DimNum>;
就是支持引用计数的动态数组啦.不过刚写了个外皮,内容还没开工,因为我最近要回家.
sorry!
[用法]
先要包含各自的头文件:
#include ";static_array.hpp";
#include ";dynamic_array.hpp";
#include ";shared_array.hpp";
1.然后就可以定义对象
cfc::static_array<;int,10>; sa1;;
cfc::static_array<;int,10, 10>; sa2;;
cfc::static_array<;int,10, 10, 10>; sa3;;
cfc::dynamic_array<;int, 1>; da1(cfc::extents[10],10);;
cfc::dynamic_array<;int, 2>; da2(cfc::extents[10][10], 10);;
cfc::dynamic_array<;int, 3>; da3(cfc::extents[10][10][10], 10);;
cfc::shared_array<;int,1>; sha1(cfc::extents[10]]);;
cfc::shared_array<;int,2>; sha2(cfc::extents[10][10]);;
cfc::shared_array<;int,3>; sha3(cfc::extents[10][10][10]);;
extents是一个数组的维度生成器,用起来的很方便,跟boost学的,不过没仔细看它的实现
,我觉得我的也不错,哈哈
2.访问元素:
sa1[0] = 0;;
da1[0] = 0;;
sa2[0][0] = 0;;
da2[0][0] = 0;;
sa3[0][0][0] = 0;;
da3[0][0][0] = 0;;
3.比较相等与否:
bool f;;
f = sa1==sb1;;
f = da1==da1;;
f = sa1==da1;;
// 说明:只提供了==和!=,别的没提供,我觉得别的意义大
4.交换:
cfc::swap(da1,db1);;
cfc::swap(sa1,sb1);;
cfc::swap(sa1,db1);;
//说明:动态数组的交换很高效,换个指针而已, :)
5.resize:
da3.resize(cfc::extents[10][100][1]);;
da3.resize(cfc::extents[10][50][1]);;
da3.resize(cfc::extents[10][10][20]);;
da3.resize(cfc::extents[10][10][10]);;
//说明:只有动态数组才能resize, 还有将来的shared_array, zz
6.赋值:
da3 = db3;;
sa1 = sb1;;
da1 = db1;;
静态数组维度不一样不能赋值,否则会引起编译错误
动态数组和丢失了静态大小成为了array_base的数组维度不一样时,赋值引发
std::length_error异常,可以捕捉到,
比较也是这样
7.作为函数的参数
还举开头的那个例子
void foo(array_base<;int,2>; &a)
{
a[0][0]=10;;
}
8.重要概念
<;子数组>;
高维数组的子类型,也就是低一维的数组.
子数组的类型为array_base,支持array_base的所有操作,但是不再支持原来数组的特定
操作子数组由[]运算符得到,
sa3[0]
da3[0] //类型均为array_base<;int,2>;
子数组还可以在取子数组
da3[0][1];;//类型为array_base<;int,1>;
[性能]
三维大小均为100的静态,动态,原生数组以及boost::multi_array.以三重循环每次隔一个
填充,
我测试的结果,速度大概是原生数组的60%,boost数组的速度是原生数组的1/5,因此速度
大概是boost的3倍.
如果用迭代器顺序访问的话,跟原生数组相比就区别不大了.但是代码要好写一点,而且直
接支持STL算法.
[实现与移植]
由于要兼顾各种编译器,而且是在VC6上做的,因此像模板偏特化等特性都不能用,需要变
通,因此相当繁琐,由此可见一个好的编译器多么重要啊.
不过话说回来,这样的代码移植性才好呢.想想连VC6都能编译的代码,移植性应该不错,
:)
[后记]
这是对以前的那个多维数组类的扩充与改进,增加了不少功能,去掉了不少限制,
现在静态数组的最大维数做到了3,动态数组的维数不限//你需要多高维数的?维数越高越
慢, :)
由于时间不多,精力和水平有限,其中的缺点和错误欢迎指正,也十分欢迎哪位能帮我进一
步提高访问速度.
谢谢!
附带测试程序,其中包括与boost::multi_array<;>;的速度比较代码.
//the end. ^=^