boost::array和boost::multi_array

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();            // 6
    boost::array<int, ELEMS>::size_type maxnum = values2.max_size();    // 6
    cout << "values2: " << num << " " << maxnum << endl;
    int arsize = sizeof(ar)/sizeof(int);    // 9
    cout << "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';
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值