Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's wrong with passing C++ iterator by reference?

I've written a few functions with a prototype like this:

template <typename input_iterator> int parse_integer(input_iterator &begin, input_iterator end); 

The idea is that the caller would provide a range of characters, and the function would interpret the characters as an integer value and return it, leaving begin at one past the last-used character. For example:

std::string sample_text("123 foo bar"); std::string::const_iterator p(sample_text.begin()); std::string::const_iterator end(sample_text.end()); int i = parse_integer(p, end); 

This would leave i set to 123 and p "pointing" at the space before foo.

I've since been told (without explanation) that it's bad form to pass an iterator by reference. Is it bad form? If so, why?

like image 634
Adrian McCarthy Avatar asked May 09 '09 20:05

Adrian McCarthy


People also ask

What happens when you dereference an iterator?

3. Dereferencing: An input iterator can be dereferenced, using the operator * and -> as an rvalue to obtain the value stored at the position being pointed to by the iterator. 4. Incrementable: An input iterator can be incremented, so that it refers to the next element in the sequence, using operator ++().

What happens if you increment the iterator past the end?

Obviously if the iterator is advanced past the last element inside the loop the comparison in the for-loop statement will evaluate to false and the loop will happily continue into undefined behaviour.

Are iterators pointers or references?

Iterators are the result of the generalization of the concept of a pointer. They can be used to iterate over the elements of an STL container and provide access to the individual elements.

Can I compare two iterators C++?

we can use == and != to compare to valid iterators into any of the library containers. The section also tells us that iterators for string and vector support relational operators (aka iterator arithmetic) which include >, >=, <, <=.


1 Answers

There is nothing really wrong, but it will certainly limit the use of the template. You won't be able to just put an iterator returned by something else or generated like v.begin(), since those will be temporaries. You will always first have to make a local copy, which is some kind of boilerplate not really nice to have.

One way is to overload it:

int parse_integer(input_iterator begin, input_iterator end,                    input_iterator &newbegin);  template<typename input_iterator> int parse_integer(input_iterator begin, input_iterator end) {     return parse_integer(begin, end, begin); }  

Another option is to have an output iterator where the number will be written into:

template<typename input_iterator, typename output_iterator> input_iterator parse_integer(input_iterator begin, input_iterator end,                              output_iterator out); 

You will have the return value to return the new input iterator. And you could then use a inserter iterator to put the parsed numbers into a vector or a pointer to put them directly into an integer or an array thereof if you already know the amount of numbers.

int i; b = parse_integer(b, end, &i);  std::vector<int> numbers; b = parse_integer(b, end, std::back_inserter(numbers)); 
like image 150
Johannes Schaub - litb Avatar answered Sep 19 '22 14:09

Johannes Schaub - litb