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.
The result of
operator*on an end iterator is undefined behavior. For any other iterator value aconst recursive_directory_entry&is returned. The result ofoperator->on an end iterator is undefined behavior. For any other iterator value aconst 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 ofrecursive_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:
incrementdirectly 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 ofThe end iterator is not dereferenceable.operator*on an end iterator is undefined behavior. For any other iterator value aconst directory_entry&is returned. The result ofoperator->on an end iterator is undefined behavior. For any other iterator value aconst directory_entry*is returned
Add a new bullet after the class synopsis in 31.12.12 [fs.class.rec.dir.itr]:
-?- Callingoptions,depth,recursion_pending,popordisable_recursion_pendingon 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().