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.
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(i)'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 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
,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()
.