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 - and maybe with code which isn't written yet. 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, openat
isn't portable between major OS platforms (ok, there are similar alternatives for Windows and Linux) and it requires an extra file descriptor. The latter might be negligible for a single one, but when you start using multiple file descriptors in parallel, and you expect to have many files, you might reach the OS limit. 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 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. If you use C and/or don't have modern libraries/frameworks at hand, you will probably have to reimplement such functions.
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 some file descriptors instead of strings might be only one possible optimization - using less files could be a different one. It makes IMHO no sense to overthink this beforehand - do yourself a favor and stop yourself from premature optizing code which hasn't been .even written yet.
So in short, by "default", I would go with strings 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 adressed by using file descriptors.