2013-02-25 99 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