2013-02-25 100 views
1

最近我看到了一些关于如何使用boost :: zip_iterator的示例代码。但是,我无法弄清楚它是如何工作的。下面是代码:关于使用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)。

+0

一个数组有N-1个元素,所以如果你解引用第N个元素,你会得到**未定义的行为**。 ''boost :: tuples :: make_tuple(si_t(s + 8),si_t(s + 9)))'这是未定义的行为,你的数组只有8个长,这意味着元素8不可访问,元素9是lala land并且不在您的范围之内。 – 2013-02-25 08:19:09

+1

要纠正@TonyTheLion所说的话:指向数组中的任何位置并指引指针是合法的;指向一个超过数组的末尾是合法的,但解引用这样的指针是未定义的行为;指向任何其他地方都是未定义的行为,即使指针从未解除引用。所以'char * p = s + 9'​​可以,只要你不解除引用'p',但'p = s + 10'就是未定义的行为。因此,这是代码是有效的指针。 – 2013-02-25 08:51:16

+0

@LucTouraille此处的数组大小为8,因此N-1是最后一个实际元素。是不是8,然后是数组的末尾? – 2013-02-25 09:13:26

回答

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 = 18 的十六进制数字的十进制表示,34 = 52AB = 171CD = 205 )。所以基本上,v包含原始十六进制字符串的基数256的表示。

+0

你很详细地解释你。最后我明白了这段代码的含义。谢谢! – user957121 2013-02-25 11:34:08