std::filesystem's parent_path() is wrong for file in current directory?

148 Views Asked by At

The traditional Unix shell utility, dirname, finds the name of the directory that contains the given file. This is useful if you want to find other sister files in the same directory. Here are a few examples:

$ dirname /some/dir/filename
/some/dir
$ dirname dirname/filename  
dirname
$ dirname filename
.

The new C++ std::filesystem's parent_path() gets this last one wrong (or so it appears):

#include <filesystem>
#include <iostream>
int main() {
    std::cout << "parent of filename: " <<
        std::filesystem::path("filename").parent_path() << '\n';
}

outputs:

parent of filename: ""

Returning an empty string instead of "." is not only different from the traditional dirname, it's also wrong when used in code which wants to tack on a "/..." on this parent to create the name of a sister files - this results in the wrong "/sister" instead of expected "./sister".

Is this a bug in std::filesystem, or deliberate behavior? Is the reason for this behavior documented somewhere?

2

There are 2 best solutions below

2
Weijun Zhou On BEST ANSWER

I won't argue with you whether this is correct or not, but if you always use std::filesystem::operator/ instead of doing string manipulation, I don't see how you will run into the issue you mention in the question.

In particular, std::filesystem::path("filename").parent_path()/std::filesystem::path("filename") gives you just "filename", not "/filename". I believe this is how the API is supposed to be used.

5
DipStax On

Using std::filesystem::path::parent_path, the result is based on the value passed to std::filesystem::path. This function is only meant to make some simple parsing and not to resolve any path.

Globaly std::filesystem::path is, as the documentation describe it, a representation of a path. If you wan't to have the same behavior as dirname, you need to look for other function available in std::filesystem namespace and build your own custom tool.

Edit:

The use of "simple" to describe the parsing strategy, mean it doesn't verify the actual value of what is parse, as the description of the function parent_path:

If has_relative_path() returns false, the result is a copy of *this. Otherwise, the result is a path whose generic format pathname is the longest prefix of the generic format pathname of *this that produces one fewer element in its iteration.

Even if it's not explicit enought (for me at least), after a few tests, the produces one fewer element in its iteration sentence translate to: produces a path to the previous directory-separators without any path resolution.