在带有斜杠的路径上返回std :: filesystem :: create_directories()的值

时间:2020-02-08 20:15:03

标签: c++ gcc clang c++17 std-filesystem

GCC(10.0.1)和Clang(11.0.0)/ MSVC(VS 16.4.3)显示了与std :: filesystem :: create_directories()有关的不同行为,当给定不存在的路径后带有斜杠论点。

更确切地说,尽管所有三个编译器确实都创建了目录,但在后一种情况下,后两个返回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/");
}

在该路径下创建目录,但在Clang / MSVC下显示false,在GCC下显示true。

哪种行为正确?

1 个答案:

答案 0 :(得分:0)

我可以确认,这不是前提条件,我认为海湾合作委员会是正确的,但我的猜测是,在这一点上澄清标准会有所帮助。

很长一段时间以来,使用尾随分隔符标记目录以将其与文件区分开是很常见的用法。而且我希望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,因此它不存在,它告诉我们它没有创建它,但是它确实存在,没有错误,并且在调用之后我们得到了证明。 / p>

查看MSVC stl的github版本,看起来它调用了CreateDirectoryW,其中包括:aa\ba\b\c,最后是a\b\c\,以及最后一个报告ERROR_ALREADY_EXISTS,导致false返回,因为似乎我们什么也没做,但是我认为这是函数的实现细节。 我的猜测是,Clang代码的工作原理类似,但是我还没有检查libc ++源代码。

标准显示为:“返回值:如果创建了新目录,则为true,否则为false。如果出现错误,则带有参数ec的签名将返回false。”

因此,如果创建了目录,则标准要求true,而不是最后一个目录,并且对于 ec 变体false表示错误,但是c通过ec告诉我们没有。

我可能仍然是错的,因为我不在任何工作组中,但我的结论是:GCC是正确的,并且似乎像MSVC和Clang中的错误。

在验证自己的实现的同时,我已经在实现之间收集了discrepancies,如果可以的话,我会“愉快地”将其添加到我的集合中。

更新:我只是深入研究其他来源,Clang / libc ++结合了基于递归parent_path()的机制,最终导致了与MSVC相同的序列,其中最后一个{{ 1}}前面有一个::mkdir("a/b/c/"),因此它假定它没有创建目录,因此报告为false。

相关问题