I would heavily avoid any solution which uses chdir
, since it is way too errorprone. It might interfer with other places in a codebase assuming the current directory wasn't changed (or worse - change it by themselves). It may also cause astonishing side effects when a program grows over time and one changes the order in which certain code sections are executed. The only cases where using chdir
makes sense is when you are 100% sure it is used exclusively at the very beginning at the startup phase of your program, in a single thread, before any other file operation takes place, and when you are sure the original current directory is restored afterwards.
This leaves you between using paths in strings or using file descriptors and openat
. But as you already noted by yourself, the Linux/Unix call openat
isn't portable between major OS platforms (to be fair, there are similar alternatives for Windows ) and it requires an extra file descriptor. The latter might be negligible for a single directory, but when you start using multiple file descriptors in parallel, and you expect to have many files, you might reach the OS limit (which AFAIK is 1024 in contemporary Linux systems, 512 under Windows, so it is indeed a somewhat limited resource). The only real advantage of openat
over strings is that one can open the descriptor, then move/rename the directory while the descriptor is still open. If that is a scenario you expect to happen, you should use openat
.
The first option uses string manipulation so is less clean in my opinion
Well, "less clean" sounds more like a superstitious feeling than some factual argument. To me, using strings (or maybe a lightweight encapsulation of strings for file paths) looks like a very clean solution as long as one uses standard functions to combine separate parts of a path. In modern C++, this should not be an issue. How to do this precisely depends on the framework and C++ version you are using. If you use C and/or don't have modern libraries/frameworks at hand, you will probably have to reimplement such functions by yourself.
but does not necessarily rely on POSIX-specific functions and therefore is probably more portable, but is the OS having to traverse the directory trees from the beginning of an absolute path going to be slower than the other options?
Maybe it is slower, but does it really matter for your specific real world application? Don't forget traversing the tree is only part of the operation, usually the most time consuming part is reading or writing the file. If you really run into a situation where you notice a measurable performance impact, and you know for sure traversing the file system tree is the bottleneck, then it is time to optimize - and using file descriptors instead of strings might be only one possible optimization (and may not bring the improvement you are looking for). Simply using less larger files instead of multiple small ones, or some lightweight file-based database can be way more effective than trying to optimize file path access. It makes IMHO no sense to overthink this beforehand. My experience is that prematurely micro-optimizing code, especially code which hasn't been written, run and tested yet is a waste of time.
So in short, by "default", I would go with strings (or some string-based file path abstractions of your framework) plus standard functions for combining parts of a path, and switch only to something different if I expect the directories to change the location during a program's run, or if I really see a notable performance issue which can be only adressed by using file descriptors.