boost::array
Boost.Array是一个模板,需要两个模板参数,分别是数据的类型和数组的大小。
boost::array<int, 1024> temp_array;
由于是模板参数,所以数组的大小必须是一个可以在编译阶段就可以推理得到的值。定义以后,就可以正常使用了。其使用方法和std::vector较类似。
// 使用某个数字填满
temp_array.fill(1);// 迭代
for (auto temp_iter = temp_array.begin(); temp_iter != temp_array.end(); ++temp_iter) {*temp_iter = 2;
}// 取某个元素
std::cout << temp_array[2] << " " << temp_array.at(3) << std::endl;// foreach
int sum_array = 0;
for (auto temp_item : temp_array) {sum_array += temp_item;
}
std::cout << sum_array << std::endl;// 逆序遍历
for (auto temp_iter = temp_array.rbegin(); temp_iter != temp_array.rend(); ++temp_iter) {*temp_iter = (temp_iter - temp_array.rbegin());
}
std::cout << temp_array[10] << std::endl;// size和max_size只返回数组的大小。而empty只在数组大小为0时返回false,在其他时候返回true
std::cout << temp_array.size() << " " << temp_array.max_size() << " " << temp_array.empty() << std::endl;
示例:
#include<iostream>
#include<vector>
using namespace std;
#include<boost/array.hpp>
#include<boost/progress.hpp>
using namespace boost;const int _SIZE = 20000;template<typename T>
void test_array_task(T _int)
{// std::cout << _int << std::endl;for (int i = 0; i < _SIZE; ++i){for (int j = 0; j < _SIZE; ++j){_int[j] = j;}}
}
// 性能比较
void test_array_performance()
{// 1. 普通数组{int _int[_SIZE];boost::progress_timer pt;test_array_task<int[]>(_int);}// 2. boost::array{boost::array<int, _SIZE> a_int;boost::progress_timer pt;test_array_task<boost::array<int, _SIZE> >(a_int);}// 3. std::vector{std::vector<int> b_int;b_int.resize(_SIZE);boost::progress_timer pt;test_array_task<std::vector<int> >(b_int);}
}void test_array()
{// 1. boost::array的构造方法const int ELEMS = 6;boost::array<int, ELEMS> values1 = {3, 1, 4, 2, 9, 8};boost::array<int, ELEMS> values2 = {2, 2, 2};boost::array<int, ELEMS> values3(values1);for(size_t i = 0; i < values3.size(); i++)cout << values3[i] << " " ;cout << endl;boost::array<int, ELEMS> values4 = values2;boost::array<int,6>::iterator itr = values4.begin();for(;itr != values4.end();++itr)cout << *itr << " " ;cout << endl;int ar[] = {9, 8, 7, 1, 2, 3, 6, 4, 5};// 2. boost::array可以获取数组的长度.// 而std::array却没有这个功能, 要用sizeof(array)/sizeof(value_type)来代替boost::array<int, ELEMS>::size_type num = values2.size(); // 6boost::array<int, ELEMS>::size_type maxnum = values2.max_size(); // 6cout << "values2: " << num << " " << maxnum << endl;int arsize = sizeof(ar)/sizeof(int); // 9cout << "arsize: " << arsize << endl;// 3. 越界异常// at: 可以用try..catch方法, 获取抛出的异常.// []: 会抛出assert错误try{values1.at(10) = 10;}catch (std::exception& e){std::cout << e.what() << std::endl;}// 抛出assert错误// values1[10];// 4. begin, cbegin, end, cend, front, end等容器的函数均可用std::copy(values1.cbegin(), values1.cend(), std::ostream_iterator<int>(std::cout, " "));std::cout << std::endl;int i1 = values1.front();int i2 = values1.back();assert(i1 == 3);assert(i2 == 8);// 5. 整体操作数据很方便values4.assign(66);
}int main()
{test_array();test_array_performance();
}
boost::multi_array
对于array,除了第一维,其它维的大小都必须是编译期确定的,N2,N3,N4必须都是编译期常量,只有n1可以是变量,这个限制与多维数组的索引方式有关——无论多少维的数组都是线性存储在内存中的
int* pOneDimArr = new int[10]; //新建一个10个元素的一维数组
pOneDimArr[0] = 0; //访问int** pTwoDimArr = new int[10][20]; //错误!
int (*pTwoDimArr)[20] = new int[i][20]; //正确
pTwoDimArr[0][0] = 0; //访问int (*pNdimArr)[N2][N3][N4] = new int[n1][N2][N3][N4];
对于
pTwoDimArr[i][j] = 0;被编译器生成的代码类似于:*( (int*)pTwoDimArr+i*20+j ) = 0;
20就是二维数组的行宽,问题在于,如果允许二维数组的行宽也是动态的,这里编译器就无法生成代码(20所在的地方应该放什么呢?)。基于这个原因,C++只允许多维数组的第一维是动态的。
boost::multi_array 是一个需要两个参数的模板:第一个参数是要存储在数组中的元素的类型。第二个参数确定数组应该有多少维,第二个参数只设置维度的数量,而不是每个维度中的元素数量。boost::extents[3][4][2]的意思是:定义一个342的三维数组。
boost::extents[3][4][2]展开为操作符调用的方式就相当于:
extents.operator .operator .operator ;
extents的工作方式:每调用一次operator [],都会返回一个extent_gen<NumRange+1>类型的对象,所以,对于boost::extents[3][4][2],依次返回的是:extent_gen<1> => extent_gen<2> => extent_gen<3>
最后一个也是最终的返回类型——extent_gen<3>。其成员ranges_中,共有[0,3)、[0,4)、[0,2)三组区间。这三组区间指定了multi_array对象的三个维度的下标区间,值得注意的是这些区间都是前闭后开的,即不包含上界值,这一点在后面的代码中能够看到。当boost::extents准备完毕后,就被传入multi_array的构造函数,用于指定各维的下标区间
关于boost::extents,可以防止用户写出错误的代码,
multi_array<int,3> A(boost::extents[3][4][2][5]); //多了一维!
无法通过编译,因为mult_array是个三维数组,而boost::extents后面却跟了四个“[]”,这显然是个错误;在语法层面,由于multi_array<int,3>的构造函数只能接受extent_gen<3>类型的参数,boost::extents[3][4][2][5]返回的却是extent_gen<4>类型的对象,于是就会产生编译错误。这种编译期的强制措施阻止了用户一不小心犯下的错误,也很清晰明了地表达(强制)了语义的需求。
boost::multi_array::array_view 是一个模板,它将视图中的维数作为模板参数。对于示例,视图的维数为 1。由于数组 a 有两个维度,因此忽略了一个维度。为了省去Boost这个词,一维数组就足够了;更多的维度会令人困惑。
与 boost::multi_array 一样,维数作为模板参数传入,每个维的大小在运行时设置。但是,对于 boost::multi_array::array_view,这不是通过 boost::extents 完成的。相反,它是通过 boost::indices 完成的,这是 Boost.MultiArray 提供的另一个全局对象。
与 boost::extents 一样,索引必须传递给 boost::indices。虽然只能将数字传递给 boost::extents,但 boost::indices 也接受范围。这些是使用 boost::multi_array_types::index_range 定义的。
对于第二个参数,boost::multi_array_types::index_range 用于定义范围。通过将 0 和 5 传递给构造函数,a 的第一个维度的前五个元素可用。范围从索引 0 开始,到索引 5 结束——不包括索引 5 处的元素。第一维中的第六个元素被忽略。
示例:
#include <boost/multi_array.hpp>
#include <iostream>
#include <cstring>
int main()
{boost::multi_array<char, 2> a{boost::extents[2][6]};typedef boost::multi_array<char, 2>::array_view<1>::type array_view;typedef boost::multi_array_types::index_range range;array_view view = a[boost::indices[0][range{0, 5}]];std::memcpy(view.origin(), "tsooB", 6);std::reverse(view.begin(), view.end());std::cout << view.origin() << '\n';boost::multi_array<char, 2>::reference subarray = a[1];std::memcpy(subarray.origin(), "C++", 4);std::cout << subarray.origin() << '\n';
}