Возвращаемое значение std :: filesystem :: create_directories () для путей с косой чертой - PullRequest
1 голос
/ 08 февраля 2020

G CC (10.0.1) и Clang (11.0.0) / MSV C (VS 16.4.3) показывают различное поведение, касающееся std :: filesystem :: create_directories (), когда несуществующий путь с в качестве аргумента указывается завершающий sla sh.

Точнее, хотя все три компилятора действительно создают каталог, последние два возвращают false в этом случае, возвращая значение std :: filesystem :: create_directories () неоднозначный (и нелогичный).

В частности, если по пути "a / b / c" не существует файла, то следующая программа,

#include <filesystem>
#include <iostream>

int main() {
    std::cout << std::boolalpha << std::filesystem::create_directories("a/b/c/");
}

создает каталог по этому пути, но печатает false в Clang / MSV C, а true в G CC.

Какое поведение является правильным?

1 Ответ

0 голосов
/ 09 февраля 2020

Я могу подтвердить, что это не вопрос предварительных условий, и, по моему мнению, G CC прав, но я предполагаю, что разъяснение стандарта по этому вопросу было бы полезно.

Для В течение долгого времени довольно часто встречается способ помечать каталоги конечным разделителем, чтобы отличать guish от файлов. И я ожидал бы, что реализация std::filesystem::create_directories вернет true, если путь, который должен быть создан, не существует до вызова и существует после вызова в результате вызова.

Давайте расширим пример немного:

#include <filesystem>
#include <iostream>
#include <system_error>

int main() {
    std::error_code ec;
    std::cout << std::boolalpha << std::filesystem::exists("a/b/c/") << "/";
    std::cout << std::filesystem::create_directories("a/b/c/", ec) << "/";
    std::cout << !!ec << "/" << std::filesystem::exists("a/b/c/");
}

Теперь мы можем использовать godbolt: https://godbolt.org/z/5883uY

И это показывает для GCC / libstdc ++ false/true/false/true, как и следовало ожидать, это не существует, он был создан вызовом create_directories, ошибки не было, и после этого он существует.

Теперь clang / libc ++ приводит к false/false/false/true, поэтому его не существует, он сообщает мы не создали его, но сделали, ошибки нет, и мы доказали после вызова.

Если посмотреть на github-версию MSV C stl, похоже, она вызывает CreateDirectoryW с: a, a\b, a\b\c и, наконец, a\b\c\, и этот последний сообщает ERROR_ALREADY_EXISTS, что приводит к возвращению false, как казалось, что мы ничего не делали, но я думаю, что это является реализацией детализации функции. Я предполагаю, что код Clang работает аналогично, но я еще не проверял источник libc ++.

И стандарт гласит: "Возвращает: true, если был создан новый каталог, иначе false. подпись с аргументом e c возвращает false, если возникает ошибка. "

Таким образом, стандарт хочет true, если был создан каталог , а не последний, и для e c вариант false сигнализирует об ошибке, но clang сообщает нам через ec не было ни одного.

Я все еще могу ошибаться, поскольку я не в любом РГ, но мой вывод: G CC прав, и это похоже на ошибку в MSV C и Clang.

Как я уже собрал несоответствия между реализациями при проверке моего если я в порядке, я "с радостью" добавлю эту в свою коллекцию, если все в порядке.

Обновление: Я просто копался в других источниках, и Clang / libc ++ работает с рекурсивом * Механизм на основе 1051 *, который в итоге приводит к той же последовательности, что и MSV C, где t ::mkdir("a/b/c/") предшествовал ::mkdir("a/b/c"), поэтому он сообщает false, поскольку предполагает, что каталоги не создавались.

...