Exception class with a char* constructor

20,988

Opinion plays a role here. The problem is that std::exception does not have a constructor that takes a string argument; this is an MSVC extension. I see two ways to go about it:

  1. Don't pass a string argument
  2. Don't use std::exception

The first case is straightforward; just use

throw std::exception();

The drawback is that you don't get a descriptive error message.

If the error message is important, using std::exception directly is not an option. In this case, you could use either std::logic_error or std::runtime_error, which inherit std::exception and do have constructors taking a string argument, so

throw std::runtime_error("Unable to format Device");

might already solve the problem. catch clauses that caught the std::exception will also catch the std::runtime_error. There is one potential problem, though: catch clauses that catch std::runtime_error would not have caught the std::exception but will catch this one.

This seems like a bit of a corner case, and it is entirely possible that it is not a problem for you. If, however, there is a possibility that along the call stack there is a catch clause that catches std::runtime_error but should not catch the exception thrown by this code, you could derive your own exception class from std::exception that does take a string argument. Because the class is new, it will not be caught by existing catch clauses. For example:

class descriptive_exception : public std::exception {
public:
  descriptive_exception(std::string const &message) : msg_(message) { }
  virtual char const *what() const noexcept { return msg_.c_str(); }

private:
  std::string msg_;
}

And then

throw descriptive_exception("Unable to format Device");

This is arguably not very pretty, and it is unlikely that it is necessary, so the more probable solution is to use std::runtime_error or std::logic_error (or a class derived from one of them).

Whether std::logic_error or std::runtime_error is more appropriate is not very clear-cut; in this case I'd probably go with std::runtime_error because the error does not seem even theoretically predictable, but given that std::domain_error and std::future_error derive from std::logic_error, it would not be entirely out of place in that hierarchy. This is, I think, a matter of opinion.

Share:
20,988

Related videos on Youtube

James Franco
Author by

James Franco

Updated on July 09, 2022

Comments

  • James Franco
    James Franco almost 2 years

    I came across the following code on VS2008

    if (!CreateProcess( NULL,
                        const_cast<LPWSTR>(ss.str().c_str()),
                        NULL,
                        NULL,
                        FALSE,
                        CREATE_NO_WINDOW|NORMAL_PRIORITY_CLASS,
                        NULL,
                        NULL,
                        &si,
                        &pi))
    {
        throw   std::exception("Unable to format Device");
    }
    

    Now I am porting the code to mingw gcc and I get the error

    error: no matching function for call to 'std::exception::exception(const char [23])'
    

    Investigating the issue I noticed that Visual Studio has a file exception which does have an exception class and does take in char*. Some of the definitions look like this

       __CLR_OR_THIS_CALL exception();
        __CLR_OR_THIS_CALL exception(const char *const&);
        __CLR_OR_THIS_CALL exception(const char *const&, int);
        __CLR_OR_THIS_CALL exception(const exception&);
        exception& __CLR_OR_THIS_CALL operator=(const exception&);
        virtual __CLR_OR_THIS_CALL ~exception();
        virtual const char * __CLR_OR_THIS_CALL what() const;
    

    My question is how should I circumvent this build issue on mingw gcc ? Should I create a new class that inherits from std::runtime_error and throw that instead ?