简体   繁体   中英

What is the purpose of std::exception::what()?

I can only think of the following situations where std::exception::what() is used:

  1. For debug purpose. In my Visual Studio to see e.what() I have to manually add it to the watch list. Isn't it better to have a member std::string (so the debugger directly shows it in the object inspector), and only include it in non-NDEBUG builds? At least they should disable what() in NDEBUG builds.
  2. Output it, eg MessageBox(e.what()) or cout << e.what() . As far as I know these messages are useless for many users. For example when I try to rename a file that doesn't exist:

    boost::filesystem::rename: 系统找不到指定的文件。: "D:\\MyDesktop\\4", "D:\\MyDesktop\\5"

    (The Chinese words means "The system cannot find the file specified.") How can the users decrypt the mixed things? Also, it is a const char* instead of something like const platform_char* , which may have unicode problems in Windows.

  3. Extract data from it, eg std::regex_match(e.what()...) . I think it's a terrible idea that shows design flaws.

So where should I use std::exception::what()? Is it useless?

A programmer is supposed to derive a class from std::exception and taylor what() to the specific requirements. Then it can be very useful.

It's also useful to report something back (eg in plain text for logging), which is why the standard mandates a concrete std::exception::what() rather than a pure virtual function.

what() is generic in the sense that it means what you want it to mean for your own exception classes. In many cases it is used only for logging, but in other cases it may provide information that can be used to recover from an exceptional situation.

So where should I use std::exception::what()? Is it useless?

The error message of std::exception is a char* because it's supposed to be an as-simple-as-possible user-facing diagnostics message giving details on the error.

For boost::system_error (and std::system_error), you can also get the OS-level error code (for which the user-friendly message is "file not found").

Valid uses:

  • if you want to identify the error type, catch the specialization std::system_error or boost::system_error and perform a switch/if on the code() function (ie instead of running a regex on the message).

  • if you want to display an explanation of the error for diagnostics (logging) or user friendliness (to console/GUI) just display the error message ( what() ).

  • std::exception is a base class (ie it has a virtual destructor). If you implement your own exception classes, follow the same pattern as std::system_error: use an error code to easily identify an error, and create your exception's base class (std::exception, std::runtime_error or std::logic_error usually) with a text message depending on the error type.

  • Ultimately, the type of the error message is char* instead of std::string, wstring or your-platform-specific-char-type because it sacrifices flexibility for reliability: with a char* everybody knows how to use it, that it has no encoding (except ASCII), that it's null terminated and once allocated, it does not fail (it doesn't generate new exceptions).

Using something that could fail (in any way) when constructing an exception would be disastrous: you would fail while creating/using a diagnostics message of your error handling code.

This means you could either not throw the exception (and your application will remain in an invalid state), or throw an exception while creating an exception instance (you really don't want that as it would discard the exception you wanted to throw (hide errors) or throw an exception with a missing or corrupted error code (which could waste months of development time in various projects to track down the wrong error).

Consider this example (unnecessarily complicated, but it makes a point):

int * p = new(nothrow) int(10); // I want to throw a complicated
                                // string message exception
if(nullptr == p)
    throw complicated_exception(std::string("error message here"));

The throw line will presumably fail: the application has so little memory available that it won't even allocate an int*, let alone a string. The result of this code is that in low memory conditions I will still get a std::out_of_memory error - one generated by std::string constructor.

std::exception is a good implementation: it provides a minimal extendable interface with a good management/restriction of failure points and it gives a good interface for extensions (such as std::system_error).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM