Are there requirements for the default constructed std::forward_iterator state for std::ranges?

75 Views Asked by At

To implement my own std::forward_iterator I must provide a default constructor for the type, since it must satisfy concept std::sentinel_for -> std::semiregular -> std::default_initializable, but actually this constructor is never used by ranges library and compiler even optimizes it out.

Am I correct in thinking that the default constructed iterator could contain any garbage, including inconsistent state of the object, since this object will never be constructed and its usage is always leads to undefined behaviour or there are some specific requirements to such iterators (like “to be valid”, “point to end()”, etc.)?

My problem is that for my iterator I can’t create consistent state if is default initialized.

It would be nice to have some reference to documentation to be sure that this is safe of not safe.

3

There are 3 best solutions below

1
cpplearner On BEST ANSWER

In general, you need to ensure that all default-constructed forward iterators compare equal to each other.

[iterator.concept.forward]:

[V]alue-initialized iterators of the same type may be compared and shall compare equal to other value-initialized iterators of the same type.

For a class with a user-defined default constructor, value-initialization is equivalent to default-initialization. Otherwise, value-initialization is equivalent to zero-initialization followed by default-initialization. ([dcl.init.general]/9)

0
YSC On

std::array<T>::iterator is, as all forward iterators are, default-constructible. Yet, it is a simple typedef over T*.

Am I correct in thinking that the default constructed iterator['s] [...] usage is always leads to undefined behaviour [...] ?

Yes, it is OK to have your iterator's default constructor construct an iterator whose dereference would lead to undefined behaviour.

0
Mestkon On

After looking up the iterator concept pages on cppreference, there doesn't seem to be any requirement for the state of a default constructed iterator.

According to cppreference, iterators are only dereferencable if they point at a valid object anyways, and comparable if they are valid iterators into the same range.

I presume the defaulted iterator is not a valid iterator into a specific range, so the only thing you can really do with it is to reassign it to some other value. Therefore, the state of the iterator doesn't matter.

Specific section on cppreference about iterators with singular values.

Iterators can also have singular values that are not associated with any sequence. Results of most expressions are undefined for singular values; the only exceptions are

  • the assignment of a non-singular value to an iterator that holds a singular value,
  • destroying an iterator that holds a singular value, and,
  • for iterators that meet the DefaultConstructible requirements, using a value-initialized iterator as the source of a copy or move(since C++11) operation.

In these cases the singular value is overwritten the same way as any other value. Dereferenceable values are always non-singular.

An invalid iterator is an iterator that may be singular.