This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of C++17 status.

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

Section: 31.12.12.2 [fs.rec.dir.itr.members], 31.12.11.2 [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 31.12.12.2 [fs.rec.dir.itr.members] the following members are specified as having the requirement "`*this != recursive_directory_iterator{}`":

- `options()`

- `depth()`

- `recursion_pending()`

- `operator++`

- `increment(...)`

- `pop()`

- `disable_recursion_pending()`

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:

- `this->options() == rhs.options()`

- `this->depth() == rhs.depth()`

- `this->recursion_pending() == rhs.recursion_pending()`

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 99 [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 returned The end iterator is not dereferenceable.

2. Add a new bullet after the class synopsis in 31.12.12 [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 31.12.12.2 [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()`.

   > > […]