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.
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.]
Change [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.
Add a new bullet after the class synopsis in 31.12.12 [fs.class.rec.dir.itr]:
-?- Callingoptions
,depth
,recursion_pending
,pop
ordisable_recursion_pending
on an iterator that is not dereferencable results in undefined behavior.
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().