使用boost :: zip_iterator对一些代码的问题

时间:2013-02-25 08:10:20

标签: c++ boost

最近我看到了一些关于如何使用boost :: zip_iterator的示例代码。但是,我无法弄清楚它是如何工作的。这是代码:

class to_hex2
{
private:
    vector<unsigned char> &v;
    char trans(const char c) const
    {
        if(c >= 'a')
            return c - 'a' + 10;
        else if(c >= 'A')
            return c - 'A' + 10;
        else
            return c - '0';
    }
public:
    to_hex2(vector<unsigned char> &_v): 
        v(_v){}

    typedef boost::tuples::tuple<const char&,const char&> Tuple;
    void operator()(Tuple const &t) const   
    {
        static char tmp;    
        tmp = trans(t.get<0>()) * 0x10;
        tmp += trans(t.get<1>());
        v.push_back(tmp);
    }
};

int main()
{
    char s[] = "1234aBcD";
    vector<unsigned char> v;
    typedef step_iterator<const char*> si_t;    
    for_each(
                boost::make_zip_iterator(
                    boost::tuples::make_tuple(si_t(s),si_t(s+1))),  
                boost::make_zip_iterator(
                    boost::tuples::make_tuple(si_t(s+8),si_t(s+9))),    
                to_hex2(v));
    std::copy(
                v.begin(),v.end(),std::ostream_iterator<unsigned char>(cout," "));
    std::cout<<std::endl<<"v.size="<<v.size();
    return 0;
}

step_iterator 是迭代器,它迭代两步而不是一步。

我的第一个问题是:由于数组s的索引最多为8(包括'\ 0':-)),是否可以写s + 9?尽管如此,代码似乎运行正常。

我的第二个问题是:由于zip_iterator可以同时迭代一个向量,这是否意味着结果是随机的?我看到的结果是不变的,如下图所示: enter image description here

最后但并非最不重要的是,有人可以告诉我结果是如何产生的(这是什么意思)因为ASCII代码中没有上下箭头(我用Google搜索并看到它here)。

1 个答案:

答案 0 :(得分:1)

只要不取消引用指针,就可以指向一个数组的结尾。这非常有用,因为C ++使用半开范围,其中排除了最后一个元素。

在您发布的代码中,s+9指向s的结尾,但从未取消引用,因此行为定义明确。

关于你的第二个问题:不,这段代码的结果不是随机的。元素将按顺序迭代,从头到尾。当文档声明zip_iterator允许对序列进行并行迭代时,并不意味着迭代将由多个线程或其他任何内容同时执行,它只意味着每次迭代将推进几个迭代器而不是仅一个迭代器。以下是for_each

的可能实现
template <typename InputIterator, typename Func>
void for_each(InputIterator first, InputIterator last, Func f)
{
    while (first != last)
    {
        f(*first);
        ++first;
    }
}

如您所见,for_each适用于单个迭代器。如果您需要一次迭代两个序列,那么您可以使用zip_iterator,它封装了几个迭代器。它的operator*返回多个值(一个元组),它的operator++递增所有迭代器,同时推进它们。

为了更好地了解代码中发生了什么,这里是一个简化版本,没有zip_iteratorfor_each

class to_hex2
{
private:
    vector<unsigned char> &v;
    char trans(const char c) const
    {
        if(c >= 'a')
            return c - 'a' + 10;
        else if(c >= 'A')
            return c - 'A' + 10;
        else
            return c - '0';
    }
public:
    to_hex2(vector<unsigned char> &_v): 
        v(_v){}

    void operator()(const char &first, const char &second) const   
    {
        static char tmp;    
        tmp = trans(first) * 0x10;
        tmp += trans(second);
        v.push_back(tmp);
    }
};

int main()
{
    char s[] = "1234aBcD";
    vector<unsigned char> v;

    to_hex2 transformer(v);

    char *first = s;
    char *second = s + 1;

    for ( ; first != s + 8 && second != s + 9 ; first += 2, second += 2)
    {
        transformer(*first, *second);
    }

    std::copy(v.begin(),v.end(),
              std::ostream_iterator<unsigned char>(cout," "));
    std::cout<<std::endl<<"v.size="<<v.size();
    return 0;
}

希望这可以清楚地表明zip_iterator只是让几个迭代器同时前进的便捷方式。

最后,要了解此代码的用途,您应该将结果打印为整数而不是字符。你应该看到这个:

18 52 171 205

是原始字符串中包含的十六进制数字的十进制表示形式(12 16 = 18 10 ,{{1} } 16 = 34 10 52 16 = AB 10 171 16 = CD 10 )。所以基本上,205包含原始十六进制字符串的基数256中的表示。