-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Description
Describe the bug
When I create a directory_iterator (or recursive_directory_iterator) and iterate it
with a range-loop (that actually creates a copy of the iterator, by calling std::filesystem::begin()),
the original iterator will be affected, but to an unexpected state, which is containing the data
of the last iterated entry (the one before the end).
That also means, that a second range-loop iteration with the same iterator, will result a single iteration of the last entry.
Command-line test case
#include <iostream>
#include <filesystem>
int main()
{
std::filesystem::directory_iterator dir_iterator(".\\test");
std::cout << "First iteration:" << std::endl;
for (auto&& entry : dir_iterator)
{
std::cout << entry.path() << std::endl;
}
std::cout << "Second iteration:" << std::endl;
for (auto&& entry : dir_iterator)
{
std::cout << entry.path() << std::endl;
}
std::cout << "Done." << std::endl;
return 0;
}
Actual behavior
Assuming that "test" directory, contains 3 files: file1.txt, file2.txt, file3.txt.
Output:
First iteration:
".\\test\\file1.txt"
".\\test\\file2.txt"
".\\test\\file3.txt"
Second iteration:
".\\test\\file3.txt"
Done
Expected behavior
I expect that the second iteration won't happen, since the dir_iterator should be equal to end.
Output:
First iteration:
".\\test\\file1.txt"
".\\test\\file2.txt"
".\\test\\file3.txt"
Second iteration:
Done
STL version
Microsoft Visual Studio Community 2019 Preview Version 16.5.0 Preview 5.0
Why it happens?
When a directory iterator is copied (default copy ctor), the member _Impl which
is a shared_ptr to the data (_Dir_enum_impl) of the current (iterated) entry, is also copied.
When the copy of the iterator reaches the end, it resets _Impl, so it is equal to end.
The original iterator, doesn't reset, hence, still has the _Impl which points to the data of the last entry,
which explains why a second iteration of the same iterator (which is copied by using begin),
starts the iteration at the last entry.
Additional thoughts
I'm not totally sure if this bug is just a really surprising/undefined behavior,
but I observed in other compiler (gcc), that this part of code other there
replaces the data of the last entry with just an empty entry, which maybe considered better,
yet unsatisfying.