2704. recursive_directory_iterator's members should require '*this is dereferenceable'

Section: 30.11.13.1 [fs.rec.dir.itr.members], 30.11.12.1 [fs.dir.itr.members] Status: C++17 Submitter: Eric Fiselier Opened: 2016-05-08 Last modified: 2017-07-30

Priority: 1

View all other issues in [fs.rec.dir.itr.members].

View all issues with C++17 status.

Discussion:

In 30.11.13.1 [fs.rec.dir.itr.members] the following members are specified as having the requirement "*this != recursive_directory_iterator{}":

This requirement is not strong enough since it still allows non-dereferenceable iterators to invoke these methods. For example:

recursive_directory_iterator it(".");
recursive_directory_iterator it_copy(it);
assert(it_copy.depth() == 0); // OK
++it;
assert(it_copy.depth() == ???); // Not OK
auto x = *it_copy; // Is this OK?

I believe these should instead require that *this is dereferenceable, however the current specification seems to say that all previous copies of it are still dereferenceable although not what they dereference to.

[fs.class.directory_iterator] p4:

The result of operator* on an end iterator is undefined behavior. For any other iterator value a const recursive_directory_entry& is returned. The result of operator-> on an end iterator is undefined behavior. For any other iterator value a const directory_entry* is returned.

Is the intention of this clause to make all non-end iterators dereferenceable?

One further complication with these methods comes from the specification of recursive_directory_iterator's copy/move constructors and assignment operators which specify the following post conditions:

If rhs is the end iterator these post conditions are poorly stated.

[2016-06, Oulu — Daniel comments]

The loss of information caused by bullet three of the suggested wording below is corrected by 2726's wording.

Voted to Ready 7-0 Monday morning in Oulu

Proposed resolution:

This wording is relative to N4582.

[Drafting note: I have not attempted to fix the specification of the copy/move constructors and assignment operators for recursive_directory_iterator]

[Drafting note: increment directly specifies "Effects: As specified by Input iterators (24.2.3)", so no additional specification is needed.]

  1. Change 30.11.12 [fs.class.directory_iterator] p4 as indicated:

    -4- The result of operator* on an end iterator is undefined behavior. For any other iterator value a const directory_entry& is returned. The result of operator-> on an end iterator is undefined behavior. For any other iterator value a const directory_entry* is returnedThe end iterator is not dereferenceable.

  2. Add a new bullet after the class synopsis in 30.11.13 [fs.class.rec.dir.itr]:

    -?- Calling options, depth, recursion_pending, pop or disable_recursion_pending on an iterator that is not dereferencable results in undefined behavior.
  3. Change 30.11.13.1 [fs.rec.dir.itr.members] as indicated:

    directory_options options() const;
    

    -17- Requires: *this != recursive_directory_iterator().

    […]

    int depth() const;
    

    -20- Requires: *this != recursive_directory_iterator().

    […]

    bool recursion_pending() const;
    

    -23- Requires: *this != recursive_directory_iterator().

    […]

    recursive_directory_iterator& operator++();
    recursive_directory_iterator& increment(error_code& ec) noexcept;
    

    -26- Requires: *this != recursive_directory_iterator().

    […]

    void pop();
    

    -30- Requires: *this != recursive_directory_iterator().

    […]

    void disable_recursion_pending();
    

    -32- Requires: *this != recursive_directory_iterator().

    […]