std::next для std::filesystem::directory_iterator
От: B0FEE664  
Дата: 11.08.21 16:34
Оценка:
Я не понимаю...

При выполнении примерно вот такого кода:
std::filesystem::directory_iterator dirIt(strDir);
std::cout << "filename = \"" << dirIt->path().filename().string() << "\" fullname: \"" << dirIt->path().string() << "\" \n"; // 1
std::next(dirIt);
std::cout << "filename = \"" << dirIt->path().filename().string() << "\" fullname: \"" << dirIt->path().string() << "\" \n"; // 2

вывод в строчках 1 и 2 должен совпадать?

А то для используемого мною (Linaro GCC 7.5-2019.12) 7.5.0 std::experimental::filesystem::directory_iterator
вызов std::next(dirIt); меняет dirIt.
Это фича или баг?
И каждый день — без права на ошибку...
Re: std::next для std::filesystem::directory_iterator
От: watchmaker  
Дата: 11.08.21 16:45
Оценка: 6 (1)
Здравствуйте, B0FEE664, Вы писали:



BFE>Это фича или баг?


Это различие между InputIterator и ForwardIterator: первый принципиально однопроходный, второй допускает несколько проходов.


BFE>вывод в строчках 1 и 2 должен совпадать?

Не должен. И работать тоже не обязан.
Так как directory_iterator — это input iterator. Инкремент может инвалидировать предыдущие ссылки, освобождать ресурсы, и т.п.
Re[2]: std::next для std::filesystem::directory_iterator
От: B0FEE664  
Дата: 11.08.21 16:53
Оценка:
Здравствуйте, watchmaker, Вы писали:

W>Так как directory_iterator — это input iterator. Инкремент может инвалидировать предыдущие ссылки, освобождать ресурсы, и т.п.

Зачем он input iterator? Трудно, что ли, было сделать ForwardIterator?
И каждый день — без права на ошибку...
Re: std::next для std::filesystem::directory_iterator
От: ArtDenis Россия  
Дата: 11.08.21 17:08
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>Я не понимаю...


BFE>При выполнении примерно вот такого кода:

BFE>
BFE>std::filesystem::directory_iterator dirIt(strDir);
BFE>std::cout << "filename = \"" << dirIt->path().filename().string() << "\" fullname: \"" << dirIt->path().string() << "\" \n"; // 1
BFE>std::next(dirIt);
BFE>std::cout << "filename = \"" << dirIt->path().filename().string() << "\" fullname: \"" << dirIt->path().string() << "\" \n"; // 2
BFE>

BFE>вывод в строчках 1 и 2 должен совпадать?

Сложный вопрос. По идее, если считать что в std::next итератор передаётся по значению, то не должен. Но видимо у std::filesystem::directory_iterator хитрая реализация, допускающая что копия итератора (переданная в next и инкрементированная) так же владеет данными итератора, и поэтому в реальности вывод не совпадает
[ 🎯 Дартс-лига Уфы | 🌙 Программа для сложения астрофото ]
Re[3]: std::next для std::filesystem::directory_iterator
От: vopl Россия  
Дата: 11.08.21 17:18
Оценка: +1
Здравствуйте, B0FEE664, Вы писали:

BFE>Здравствуйте, watchmaker, Вы писали:


W>>Так как directory_iterator — это input iterator. Инкремент может инвалидировать предыдущие ссылки, освобождать ресурсы, и т.п.

BFE>Зачем он input iterator? Трудно, что ли, было сделать ForwardIterator?

Именно так, трудно. Вот посмотри на низлежащие АПИ на основе которых этот directory_iterator::increment реализуется (пару примеров:
https://www.opennet.ru/man.shtml?topic=readdir&amp;category=3&amp;russian=5
https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-findnextfilea )
— они обычно реализуют семантику именно input iterator, таким образом directory_iterator легче делать именно как тонкий врапер над такими АПИ, без дополнительного функционала внутри, который бы повышал уровень до ForwardIterator
Re[2]: std::next для std::filesystem::directory_iterator
От: vopl Россия  
Дата: 12.08.21 07:13
Оценка:
Здравствуйте, ArtDenis, Вы писали:

AD>Здравствуйте, B0FEE664, Вы писали:


BFE>>Я не понимаю...


BFE>>При выполнении примерно вот такого кода:

BFE>>
BFE>>std::filesystem::directory_iterator dirIt(strDir);
BFE>>std::cout << "filename = \"" << dirIt->path().filename().string() << "\" fullname: \"" << dirIt->path().string() << "\" \n"; // 1
BFE>>std::next(dirIt);
BFE>>std::cout << "filename = \"" << dirIt->path().filename().string() << "\" fullname: \"" << dirIt->path().string() << "\" \n"; // 2
BFE>>

BFE>>вывод в строчках 1 и 2 должен совпадать?

AD>Сложный вопрос. По идее, если считать что в std::next итератор передаётся по значению, то не должен. Но видимо у std::filesystem::directory_iterator хитрая реализация, допускающая что копия итератора (переданная в next и инкрементированная) так же владеет данными итератора, и поэтому в реальности вывод не совпадает


https://en.cppreference.com/w/cpp/filesystem/directory_iterator/increment

directory_iterator& operator++();
directory_iterator& increment( std::error_code& ec );
(since C++17)
Advances the iterator to the next entry. Invalidates all copies of the previous value of *this.


Повезло что оно вообще работает, а могло бы на второй строке посыпаться с диагностикой типа "не могу разыменовать невалидный итератор"
Re[2]: std::next для std::filesystem::directory_iterator
От: ArtDenis Россия  
Дата: 12.08.21 09:06
Оценка:
Здравствуйте, ArtDenis, Вы писали:

AD>Сложный вопрос. По идее, если считать что в std::next итератор передаётся по значению, то не должен.


Только сейчас заметил, что очепятался. Хотел написать "то должен"
[ 🎯 Дартс-лига Уфы | 🌙 Программа для сложения астрофото ]
Re[3]: std::next для std::filesystem::directory_iterator
От: ArtDenis Россия  
Дата: 12.08.21 09:22
Оценка:
Здравствуйте, vopl, Вы писали:

V>

V>Advances the iterator to the next entry. Invalidates all copies of the previous value of *this.

V>Повезло что оно вообще работает, а могло бы на второй строке посыпаться с диагностикой типа "не могу разыменовать невалидный итератор"

Не совсем ясно из описания, обращение к dirIt после std::next — это UB или не UB?
[ 🎯 Дартс-лига Уфы | 🌙 Программа для сложения астрофото ]
Re[4]: std::next для std::filesystem::directory_iterator
От: vopl Россия  
Дата: 12.08.21 12:27
Оценка:
Здравствуйте, ArtDenis, Вы писали:

AD>Здравствуйте, vopl, Вы писали:


V>>

V>>Advances the iterator to the next entry. Invalidates all copies of the previous value of *this.

V>>Повезло что оно вообще работает, а могло бы на второй строке посыпаться с диагностикой типа "не могу разыменовать невалидный итератор"

AD>Не совсем ясно из описания, обращение к dirIt после std::next — это UB или не UB?


Обращение к dirIt после std::next это нарушение условий его использования, инвалидные итераторы нельзя разыменовывать (тут табличка https://en.cppreference.com/w/cpp/named_req/InputIterator, она же в стандарте [tab:inputiterator]). UB или не UB — как по мне так уже и не важно, потому что нарушены условия, уже все плохо.
Re[3]: std::next для std::filesystem::directory_iterator
От: watchmaker  
Дата: 12.08.21 13:35
Оценка: +2
Здравствуйте, vopl, Вы писали:

V>Повезло что оно вообще работает, а могло бы на второй строке посыпаться с диагностикой типа "не могу разыменовать невалидный итератор"


Наоборот же.
Везёт — это когда в случае допущенной ошибки получаешь диагностику. И вдвойне везёт, если это происходит рядом с местом ошибки (на этой самой "второй строке").

А когда код порождает UB, которое не ловится стандартным санитайзером (ubsan) и при этом проявляется не в виде падения, а выдаёт что-то похожее на нормальный ответ, то это явно хуже вариант, так как требует долгой отладки. Хуже этого только плавающие баги, которые не получается надёжно воспроизводить
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.