我实现了一个双向迭代器,但是它没有对数据结构进行操作,而是返回了一个数学序列,该序列可以在两个方向上进行迭代计算。实际上,我正在使用int上的++和-遍历整数。这意味着数据不会存储在不同的结构中,因此,当迭代器超出范围时,值也不会存储。

不过,我希望下一个代码(失败的示例最少)示例能够正常工作,因为迭代器始终处于作用域内。但这不起作用:(

#include <iostream>
#include <iterator>
#include <vector>

class my_iterator : public std::iterator<std::bidirectional_iterator_tag, int> {
  int d_val = 12;
public:
  my_iterator  operator--(int) { std::cout << "decrement--\n"; return my_iterator(); }
  my_iterator &operator--()    { std::cout << "--decrement\n"; return *this; }
  my_iterator  operator++(int) { std::cout << "increment++\n"; return my_iterator(); }
  my_iterator &operator++()    { std::cout << "++increment\n"; return *this; }

  int &operator*() { std::cout << "*dereference\n"; return d_val; }

  bool operator==(my_iterator const  &o) { return false; }
  bool operator!=(my_iterator const  &o) { return true ; }
};


int main() {
  auto it = std::reverse_iterator<my_iterator>();
  int &i = *it;
  if (true)
  {
    std::cout << i << '\n';
  }
  else
  {
    std::vector<int> vec;
    vec.push_back(i);
    std::cout << vec[0] << '\n';
  }
}

资料来源:http://ideone.com/YJKvpl

如果由valgrind正确检测到,则if分支会导致内存冲突:
--decrement
*dereference
==7914== Use of uninitialised value of size 8
==7914==    at 0x4EC15C3: ??? (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.20)
==7914==    by 0x4EC16FB: std::ostreambuf_iterator<char, std::char_traits<char> > std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char> > >::_M_insert_int<long>(std::ostreambuf_iterator<char, std::char_traits<char> >, std::ios_base&, char, long) const (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.20)
==7914==    by 0x4EC1C7C: std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char> > >::do_put(std::ostreambuf_iterator<char, std::char_traits<char> >, std::ios_base&, char, long) const (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.20)
==7914==    by 0x4ECEFB9: std::ostream& std::ostream::_M_insert<long>(long) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.20)
==7914==    by 0x40087B: main (divine.cc:25)
==7914==
==7914== Conditional jump or move depends on uninitialised value(s)
==7914==    at 0x4EC15CF: ??? (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.20)
==7914==    by 0x4EC16FB: std::ostreambuf_iterator<char, std::char_traits<char> > std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char> > >::_M_insert_int<long>(std::ostreambuf_iterator<char, std::char_traits<char> >, std::ios_base&, char, long) const (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.20)
==7914==    by 0x4EC1C7C: std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char> > >::do_put(std::ostreambuf_iterator<char, std::char_traits<char> >, std::ios_base&, char, long) const (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.20)
==7914==    by 0x4ECEFB9: std::ostream& std::ostream::_M_insert<long>(long) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.20)
==7914==    by 0x40087B: main (divine.cc:25)
==7914==
==7914== Conditional jump or move depends on uninitialised value(s)
==7914==    at 0x4EC1724: std::ostreambuf_iterator<char, std::char_traits<char> > std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char> > >::_M_insert_int<long>(std::ostreambuf_iterator<char, std::char_traits<char> >, std::ios_base&, char, long) const (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.20)
==7914==    by 0x4EC1C7C: std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char> > >::do_put(std::ostreambuf_iterator<char, std::char_traits<char> >, std::ios_base&, char, long) const (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.20)
==7914==    by 0x4ECEFB9: std::ostream& std::ostream::_M_insert<long>(long) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.20)
==7914==    by 0x40087B: main (divine.cc:25)
==7914==
12
==7914==
==7914== HEAP SUMMARY:
==7914==     in use at exit: 0 bytes in 0 blocks
==7914==   total heap usage: 0 allocs, 0 frees, 0 bytes allocated
==7914==
==7914== All heap blocks were freed -- no leaks are possible
==7914==
==7914== For counts of detected and suppressed errors, rerun with: -v
==7914== Use --track-origins=yes to see where uninitialised values come from
==7914== ERROR SUMMARY: 5 errors from 3 contexts (suppressed: 0 from 0)

else分支不会导致内存冲突,或者至少不会影响我的valgrind。但是, vector 中存储的值是“随机”:
--decrement
*dereference
-16777520

我对发生的事情感到有些惊讶。迭代器应始终处于作用域内,但该引用似乎已失效。为什么在打印12时出现内存冲突,或者为什么在存储不同于12的内存时却没有内存冲突?

最佳答案

reverse_iterator不适用于所谓的“隐藏式迭代器”,该迭代器返回对自身内部事物的引用。 operator*reverse_iterator生成包装的迭代器的拷贝,将其递减,然后返回解引用该拷贝的结果。因此,如果取消引用迭代器返回对自身内部内容的引用,则该引用将变得悬而未决。

在C++ 11规范中曾尝试使其工作,但事实证明,如果不为非隐藏式迭代器添加大量开销*,那么就不可能实现the specification was reverted to the C++03 version

*为了支持“隐藏式迭代器”,必须添加一个额外的数据成员来存储递减的当前迭代器,从而使reverse_iterator的大小增加一倍;然后必须使用某种形式的同步,因为operator *const-因此必须可以同时从多个线程中调用而不会引起数据争用-但必须修改此附加数据成员。对于这种不常见的用例,要添加到所有reverse_iterator中会产生很多开销。

09-10 04:05
查看更多