cplusplus / draft

C++ standards drafts
http://www.open-std.org/jtc1/sc22/wg21/
5.73k stars 751 forks source link

[iterator.requirements.general] Allowed operations on singular iterators needs rephrasing #2381

Open jwakely opened 6 years ago

jwakely commented 6 years ago

We have a sentence that tries to enumerate all the things allowed on singular iterators. For the last clause in the sentence it's unclear which operand is the singular iterator that is the subject of the sentence. Worse, the next sentence (after the note) says "In these cases the singular value is overwritten" which is completely untrue for 2/3 of "these cases".

Maybe split it into bullets (changes to existing wording highlighted in bold):

Results of most expressions are undefined for singular values; except for the following cases:

  • Destruction of an iterator that holds a singular value.

  • Assignment of a non-singular value to an iterator that holds a singular value, in which case the singular value is overwritten the same way as any other value.

  • For iterators that satisfy the Cpp17DefaultConstructible requirements, using a value-initialized singular iterator as the source of a copy or move operation. [Note: This guarantee is not offered for default-initialization, although the distinction only matters for types with trivial default constructors such as pointers or aggregates holding pointers. — end note]

Dereferenceable values are always non-singular.

For the third bullet, we only need to define what happens for value-initialized iterators that also happen to be singular, because otherwise we don't need to make an exception for them here. There could be a type where a value-initialized iterator is not singular (it might refer to some global sequence by default).

Regarding the note, is it true that "the distinction only matters for types with trivial default constructors such as pointers or aggregates holding pointers"? What matters for [dcl.init] is whether the constructor is user-provided, not trivial. For example:

struct Iter {
    std::string unused;
    int* ptr;
    int& operator*() { return *ptr; }
    // ...
};

This has a non-trivial default constructor, but the distinction between default-initialization and value-initialization matters.

CaseyCarter commented 6 years ago

[Note: This guarantee is not offered for default-initialization, although the distinction only matters for types with trivial default constructors such as pointers or aggregates holding pointers. — end note]

Nitpick: There's no guarantee that default-initialization is equivalent to value-initialization for a type with non-trivial default-initialization (for example).

Regarding the note, is it true that "the distinction only matters for types with trivial default constructors such as pointers or aggregates holding pointers"?

Oops - I see you've already noticed this as well. Consider my first comment as corroboration.