简体   繁体   中英

iterator as function input in C++?

I have problem in the following simple code:

  void foo (vector<int>:: iterator it, vector<int> n)
  {
       vector<int>:: iterator it2 = it +1;
       while (it2!=n.end())
       {
           cout<<*it2<<endl;
           it2++;
       }
  }
  main()
  {
        vector<int> m{1,2,3,4};
        vector<int>:: iterator it = m.begin();
        foo (it, m);
  }

I expected to have 2, 3 and 4 in the Terminal, but I got some stupid results in output. Is it basically possible to use iterators as functions' input? What is wrong in this piece of code? and How can I make it correct?

You pass vector<int> n as a copy. Thus your it2 points to a different vector (the one that was created in main ). Your check it2!=n.end() is invalid since it2 is an iterator to another vector.

Passing n by reference is one solution. Other would be passing the end iterator instead of vector.

To pass your vector as a const reference:

void foo (vector<int>:: iterator it, const vector<int>& n)

To pass an end iterator:

void foo (vector<int>::iterator it, vector<int>::iterator end)
{
 ...
     while ( it2 != end )
 ...
}

You have two problems: one is that you're passing a copy of your vector argument, as Satus and yeputons already pointed out.

The second problem is that the first line of foo is already illegal if the argument is empty. That is, even the trivial fix

void foo (vector<int>:: iterator it, vector<int> &n)
{
   vector<int>:: iterator it2 = it +1;

is wrong if it == n.end() .

The correct design is the one used for all the library algorithms, and for the same reason: that it can correctly express empty ranges.

void foo (vector<int>::iterator begin, vector<int>::iterator end)
{
   if (begin == end) return;
   for (auto i = begin; i != end; ++i)
   {
       cout<<*i<<endl;
   }
}

Your weird skipping-the-first-element design makes it a bit ugly still, a nicer approach is to have some utility help skip the first element, and then use copy:

template <typename Iterator>
Iterator try_advance(Iterator i, int count, Iterator end)
{
  for (; count-- > 0 && i != end; ++i)
    ;
  return i;
}


void foo (vector<int>::iterator begin, vector<int>::iterator end)
{
   // skip first element of a non-empty range
   // leave an empty range un-damaged
   begin = try_advance(begin, 1, end);
   std::copy(begin, end, std::ostream_iterator<int>(std::cout, '\n'));
}

Yes, it's possible. But mind that iterators are tied to their container.

Second parameter of your function is copy-constructed from argument, ie vector<int> n is a copy of vector<int> m defined in main . So, your function tries to compare iterator with another iterator ( .end() ) from a different container. You'd better pass both begin/end iteratos instead of container.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM