std::filesystem::exists is used to check "if the given file status or path corresponds to an existing file or directory." In my code, I am using the definition with the following signature:
bool exists( const std::filesystem::path& p, std::error_code& ec ) noexcept;
My question is: if the function returns the boolean value true
, do I still need to check the value of the error code ec
? Or can I assume that, if std::filesystem::exists
returns true
, then there is no error and (bool)ec
is false
?
For example, suppose I have the following:
std::error_code ec;
std::filesystem::path fpath = "fname";
bool does_exist = std::filesystem::exists(fpath, ec);
if (does_exist) {
...
}
Is it necessary to check that (bool)ec == false
within the if (does_exist) { ... }
block?
The std::filesystem
library evolved out directly from the corresponding Boost library. As several functions in the Boost libraries (such as Boost ASIO) it offers two interfaces that use a different type of error handling
bool exists(std::filesystem::path const& p);
bool exists(std::filesystem::path const& p, std::error_code& ec) noexcept;
The first version uses exceptions (that have to be caught with a try... catch
construct) while the second one does not but instead one has to evaluate the error codes. This error code might then contain additional information about the precise reason of the failure and help with debugging if the function returns false
.
The overload that does not take a std::error_code& parameter throws filesystem_error on underlying OS API errors, constructed with p as the first path argument and the OS error code as the error code argument. The overload taking a std::error_code& parameter sets it to the OS API error code if an OS API call fails, and executes ec.clear() if no errors occur. Any overload not marked noexcept may throw std::bad_alloc if memory allocation fails.
If the function returns true
on the other hand it is safe to assume that the path exists.
Error codes are more lightweight and in particular convenient for real-time performant code, numerical simulations and high-performance applications. In these cases one might turn off exception handling entirely for the compilation process just to have better performance. On the other hand error codes are often harder to maintain as for nested code - if a routine fails in some subfunction - you will have to pass the error code through several layers to where the error should be handled. Exceptions in this regard are easier maintainable.