如果你是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 );
}
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之功,这点瑕疵也完全可以忽略。