What exception should I throw in the case of an incorrect file name?

I have this constructor that accepts a string for a filename. In order to verify that the file is accessible, I am using a std::ifstream to check if the file can be opened. However, in the case that it does not open, I'm left wondering what exception I should throw.

Here are the choices I see:

1. Throw a generic std::exception with a custom error message; Seems ok for the most part. However, the program I am making is meant to be used as a library, meaning that users will probably not be expecting such an exception.

2. Derive from std::exception (Or some other subclass), and throw said exception (It might be called something like BadFileName). However, this seems like a waste of a class, as I'm only going to be using it once, and it only seems to serve one specific purpose.

3. Use one of the already defined subclasses of std::exception, such as std::out_of_range or such. However, I am unsure which of these to use.

4. Define a universal exception for anything wrong that happens with my library. This is ok, but I feel like once again, I'm left with a class that is too generic.

Currently, I'm leaning towards option 4, but I wanted to get a second opinion before fully delegating myself towards it.

What are all of your thoughts?
What about http://www.cplusplus.com/reference/stdexcept/invalid_argument/

If you are just trying to get a valid filename from the user, then an exception is not needed:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>
#include <fstream>
#include <string>

bool file_can_be_opened(const std::string& filename) {
    std::ifstream fin(filename);
    return static_cast<bool>(fin);
}

int main() {
    std::string filename;
    do {
        std::cout << "Enter the filename: ";
        std::cin >> filename;
    } while (!file_can_be_opened(filename));
    std::cout << "File can be opened\n";
}

Last edited on
@tpb, it seems you have misunderstood what I am trying to say.

In my first option, I specifically mention that I am making a library; as such, the console may or may not be available. Even if it was, it would be confusing for the user of said library to suddenly find themselves being asked for a correct file name in the console, mixed in with their actual output.
in tpb's example, the function is the library, the user writes the error for you. But it is a overly simple example.

You could make the user load the file for you, and pass an already valid ifstream as a file for the init function. Very good if there is only 1 other possible error, which is from curruption of data.

If you want various errors and you want to avoid exceptions, I could also see simple error callback system. The client just defines a function with a string as a parameter, or if no callback is made you can just call stdout all you want, and now the simple bool system works again!

Otherwise there is nothing wrong with exceptions, just call exceptions in any way you want, it all leads to the same result.
LIBNAME: Something Happened!
.

I guess you could allow users to overwrite specific exceptions in catch chains, but its quite rare for people to actually care about that, other than std's code since sometimes its not something a non-programmer should ever read like casting error or out of bounds, and for a programmer, WHERE did it happen? line? file?

So you have to be careful to not leak any std related exceptions out of your library.
I think that an invalid file name (eg. the file does not exist because it was deleted) would be a run-time error rather than a logical error.

If more information about the cause of the error is to be carried by the exception object, one could use the filesystem library and the ready made std::filesystem::filesystem_error
https://en.cppreference.com/w/cpp/filesystem/filesystem_error
Last edited on
Since you don't want to make an assumption that a "console" exists how can you make an assumption that a file system exists, or that you even have an operating system?

You don't need to assume a console exists to assume a file system exists. GUI applications are fairly common, I would have expected, and very few have a console.
BTW. If you can't open a file it doesn't mean that it doesn't exist. The file can be corrupt or open in a different process or ....
Personally I would create a FileError class and pass strerrror(errno).
I have this constructor that accepts a string for a filename. In order to verify that the file is accessible, I am using a std::ifstream to check if the file can be opened. However, in the case that it does not open, I'm left wondering what exception I should throw.

This really depends on what caused the exception and whether or not you can recover from the error. IMO, throwing an unhandled exception from a library should be avoided whenever possible.

In this case I would recommend that you consider having the user pass a valid stream instead of a filename, let the user code worry about the actual file name and properly opening the stream. Stream errors can be very difficult to diagnose because of the many varied failures.

By the way just because you have a GUI program doesn't mean that you don't have a console or in this case the std::err stream, where you should be "throwing" your error diagnostics in the first place. And don't forget that std::cout and std::err can usually be redirected to allow the user to "see" why things are failing.

Well, the problem is that taking in a stream directly from input isn't really possible. In the code I'm using, which also depends on another library, I am:

1. Taking in a file name from a constructor
2. Checking if the file name is valid, etc, etc.
3. Passing said valid file name (Unless its possible to extract a filename from a file stream) to a library that mine is using internally as a dependency (A file parser for a specific format, to be specific).

The reason I want to check for the validity is to make sure that I keep the user seeing the dependency to the minimum. If I don't check, and the file is NOT valid, the user might have to see an exception from an internal library (I can confirm this), which, I don't want the user to see.
IMO, throwing an unhandled exception from a library should be avoided whenever possible.
Why ?
Exceptions are the normal way to handle errors. The caller can easily catch it, display it on the console, or in a dialog.
Even if you pass a stream what will you do if the stream gets in an invalid state ?
Exceptions are the normal way to handle errors.
This is debatable. In some programs you may not be concerned about handling error situations; the program should just exit as soon as any kind of error happens. In other programs errors may happen routinely, to such a degree that throwing an exception for each one may be prohibitively expensive.
Exceptions are the normal way to handle errors.
This is debatable.
Using exceptions for error handling makes you code simpler, cleaner, and less likely to miss errors.

http://www.stroustrup.com/bs_faq2.html#exceptions-why

What would you recommend ?
Last edited on
It depends on how the program is structured and what has failed. I usually use exceptions for harder failures than normal errors, generally unrecoverable ones.
For example, file not found:
* Is the file that wasn't found required for the program to work at all? Throw an exception.
* Is the file just normal user input? Return an error.
* Is the file user input, but one that without which the program has nothing to do (e.g. the program was invoked as program file.bin)? Throw an exception.

Another rule of thumb I usually use is that an exception should be thrown if there's no reasonable way for the caller to fix the problem.

Something that I'm surprised Stroustroup mostly glossed over is that while it's true that the presence of exception handling code has little overhead, throwing doesn't, and like I said a function that routinely fails can become very expensive if it throws just to communicate that it failed.
RUNNER PRO AGARIO wrote:
I specifically mention that I am making a library;

Back to the original topic of this thread, both #3 (existing subclass of std::exception, such as filesystem_error that JLBorges mentioned) and #2 (custom exception type derived from std::exception) are common in library code. Some libraries build large custom hierarchies of exception types.

There's another option that many libraries use when they are concerned about throwing across DLL boundaries: throw something you know about (such as an exception from a custom hierarchy), but on the user-facing API boundary, catch everything and convert to error code. For example, here's scintilla's user-facing API: https://github.com/mirror/scintilla/blob/3c53389b57a98355a4ba90bf1a17a27cb8ffbe88/qt/ScintillaEditBase/ScintillaQt.cpp#L674-L678 all exceptions become SC_STATUS_FAILURE except bad_alloc, which becomes SC_STATUS_BADALLOC.

If I don't check, and the file is NOT valid, the user might have to see an exception from an internal library (I can confirm this), which, I don't want the user to see.


Just check if the ifstream is valid in your library. BOOM. No exception from an invalid ifstream. Person has 10 bytes left of memory in his hard drive? Catch the bad alloc or whatever exception and make it readable.
Topic archived. No new replies allowed.