HelloWorld
HelloWorld

Reputation: 1863

How to use recursive_directory_iterator(..) without exceptions in C++

I use recursive_directory_iterator to iterate through directories. The iterator seems to throw exceptions when the passed path does not exist. Is there a way to use the iterator without enabling exceptions?

// try / catch can't be used here
for (auto const& dir_entry : fs::recursive_directory_iterator("I-dont-exist"))
{
    std::cout << dir_entry << '\n';
}

Upvotes: 1

Views: 717

Answers (2)

Paul Floyd
Paul Floyd

Reputation: 6906

I don't think that either of the previous answers address the problem.

The issue is that the range-based for loop implicitly uses operator++() to increment the iterator. See https://en.cppreference.com/w/cpp/language/range-for

However, if you want the non-throwing iterator, the signature is

recursive_directory_iterator& increment( std::error_code& ec );

(see https://en.cppreference.com/w/cpp/filesystem/recursive_directory_iterator/increment).

That means that you need to write an old-fashioned for loop.

Something like this

  std::error_code ec;
  using recursive_directory_iter =
      std::filesystem::recursive_directory_iterator;
  auto dirEntry = std::filesystem::begin(recursive_directory_iter(dir, ec));
  for ( ; dirEntry != std::filesystem::end(recursive_directory_iter(dir, ec)); dirEntry.increment(ec)) {

Upvotes: 0

Sam Varshavchik
Sam Varshavchik

Reputation: 118292

From cppreference.com's writeup:

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.

The reason why this constructor is not marked noexcept is most likely because, pedantically, it might throw an exception for reasons unrelated to a nonexistent directory or path. This only guarantees no exceptions in case of filesystem issues, such as your nonexistent directory. Since you are looking to prevent exceptions getting thrown for that reason, this should work.

Your next task is to construct std::filesystem::path without throwing an exception.

std::filesystem::path constructors are defined as follows: "May throw implementation-defined exceptions", a carte-blanche for throwing an exception if they fancy to, for any reason.

But, practically, this is referring to filesystem paths that are, well, valid paths. Attempting to construct a path for "/:\WINDOWS\SYSTEM" on MS-Windows will likely earn you one of those "implementation-defined" exceptions.

If you feed a path string that's a valid path string, on your operating system, you're not going to get a thrown exception.

Finally, std::filesystem::path's constructors are implicit. Avoiding exceptions, for your use case, boils down to:

  1. Passing a valid path when constructing a recursive directory iterator. It's up to you to validate it according to your operating system filenames' rules.

  2. Using the overload that takes a reference to an error code object, as an additional parameter.

Upvotes: 1

Related Questions