Search code examples
c++iterator

Don't understand how std::iterator works in list initialization


I have trouble with using std::vector::iterator. First I defined a struct:

template <typename T>
struct VecIter {
  VecIter(std::vector<T>::iterator &&it_, size_t remain_):
    it(it_), remain(remain_) {}

  std::vector<T>::iterator &it;
  size_t remain;

  T& operator * () {
    return *it;
  }
};

It's just a wrapper of a regular iterator. Here is a test class:

template <typename T>
class testA {
  public:
    testA(std::vector<T> &a) {
      stack.push_back({a.begin(), a.size()});
    }

    std::vector<VecIter<T>> stack;
};

The constructor takes a std::vector as input and initialize our iterator wrapper. Here comes the test section:

TEST(TestIterator, test_iter_in_stack) {
  std::vector<int> a{3, 2, 1};

  testA<int> sol(a);
  auto x = sol.stack[0];
 
  auto it = x.it;  // extract the iterator
  cout << *it << "\n";  // segmentation fault here...
  it++;
  cout << *it << "\n";
}

My question is why *it here would cause a segmentation fault? I suspect the list initialization stack.push_back({a.begin(), a.size()}) didn't successfully pass the iterator in.

I expect the test should print out 3 and 2. Any comments is welcome. Thanks!


Solution

  • VecIter::it is a dangling reference to the temporary object returned by a.begin(). You should change std::vector<T>::iterator &it to std::vector<T>::iterator it.

    In general, iterators are likely not much more than a pointer, passing and storing them by reference is not likely to be necessary. The standard library generally passes them by value, e.g. in the std::vector constructor.