Why are C++ iterators required to return a reference?

I'm implementing an iterator that iterates over the results of a generator function rather than over a data structure in memory such as a vector or map.

Reading through the final working draft for C++17 §27.2.3, the return type of the dereference operator for an input iterator (and by extension, most other iterators) a forward iterator is required to be a reference. This is fine for items that exist in the data structure the iterator is iterating over. However, because I'm not using a data structure and am calculating each item when the dereference operator is called, I don't have a valid reference to return; the calculated item is destroyed when the operator returns. To work around this, I am storing the result of the calculation in the iterator itself and returning a reference to the stored result. This works fine for my use case, but has issues of its own when used with arbitrary user-defined types.

I can understand iterators being allowed to return a reference, but why would this be a requirement for non-mutating iterators? Did the writers of the standard not consider generators and on-the-fly transformations to be valid use cases for iterators? Would returning a value instead of a const reference cause any actual harm?

[edit]: I'm asking more out of curiosity about why the standard is written the way it is, since I already have a perfectly good workaround.

Upvotes: 21

Views: 4155

Answers (2)

Catskul
Catskul

Reputation: 19258

It appears that as of c++20 that requirement has been relaxed:

Notes:

Unlike the LegacyForwardIterator requirements, the forward_iterator concept does not require dereference to return a reference.

https://en.cppreference.com/w/cpp/iterator/forward_iterator https://isocpp.org/files/papers/N4860.pdf#page=920

Upvotes: 2

Brian Bi
Brian Bi

Reputation: 119382

Dereferencing an input iterator is not required to yield a glvalue (that is, return a reference). The input iterator requirements say that the return type when dereferencing must be "reference, convertible to T" but nowhere does it say that reference must be a reference type.

However, dereferencing a forward iterator is required to yield a glvalue:

if X is a mutable iterator, reference is a reference to T; if X is a constant iterator, reference is a reference to const T,

So go ahead and write your iterator that generates elements on the fly, but it can only be an input iterator, not a forward iterator. For many algorithms this is sufficient (e.g., std::for_each and std::all_of).

Upvotes: 17

Related Questions