How to Throw Std::Exceptions with Variable Messages

How to throw std::exceptions with variable messages?

Here is my solution:

#include <stdexcept>
#include <sstream>

class Formatter
{
public:
Formatter() {}
~Formatter() {}

template <typename Type>
Formatter & operator << (const Type & value)
{
stream_ << value;
return *this;
}

std::string str() const { return stream_.str(); }
operator std::string () const { return stream_.str(); }

enum ConvertToString
{
to_str
};
std::string operator >> (ConvertToString) { return stream_.str(); }

private:
std::stringstream stream_;

Formatter(const Formatter &);
Formatter & operator = (Formatter &);
};

Example:

throw std::runtime_error(Formatter() << foo << 13 << ", bar" << myData);   // implicitly cast to std::string
throw std::runtime_error(Formatter() << foo << 13 << ", bar" << myData >> Formatter::to_str); // explicitly cast to std::string

C++ Exceptions with message

You can take advantage of std:string

class LoadException: public std::exception {
private:
std::string message_;
public:
explicit LoadException(const std::string& message);
const char* what() const noexcept override {
return message_.c_str();
}
};

LoadException::LoadException(const std::string& message) : message_(message) {

}

Then the C++ scoping will take care of cleaning things up for you

Easy way of constructing information message for throwing std::exception using preprocessor macros

Just do this:

throw std::logic_error(std::string{} + "Whoops! Error in (" +
__func__ + ") " + __FILE__ + ":" + std::to_string(__LINE__));

live example

Sometimes you can format it like the IDE does its own error messages, then get double-click support.

throw std::logic_error(std::string{} + __FILE__ + "(" + std::to_string(__LINE__) + "): [" + __func__ +"] " + "Whoops! Error!  Whodathunk.");

or somesuch.

template<class E>
[[noreturn]] void fancy_throw( std::string msg,
char const* file, char const* function,
std::size_t line
) {
throw E( std::string{} + file + "(" + std::to_string(line) + "): [" +
function + "] " + msg );
}
#define EXCEPTION( TYPE, MESSAGE ) \
fancy_throw<TYPE>( MESSAGE, __FILE__, __func__, __LINE__ )

and we get:

EXCEPTION( std::logic_error, "Whoops! Error!  Whodathunk." );

live example

I think this is poor. Instead, we can have a SOURCE_ERROR macro:

inline std::string make_source_error( std::string msg,
char const* file, char const* function,
std::size_t line
) {
return std::string{} + file + "(" + std::to_string(line) + "): [" +
function + "] " + msg;
}
#define SOURCE_ERROR(...) make_source_error(__VA_ARGS__, __FILE__, __func__, __LINE__ )

which places flow control outside of macros, but does the string building with the tokens inside the macro, and builds the string inside a normal function.

Only the things that must be done in a macro (or copy/pasted everywhere we use it) are done in a macro here. Which is how it should be.

live example

... and __VA_ARGS__ are there because the macro language doesn't understand some uses of , in C++.

Throw exception on missing function overload with std::variant instead of compile time error

I found a solution from this site

template <class ...Fs>
struct overload : Fs... {
overload(Fs const&... fs) : Fs{fs}...
{}

using Fs::operator()...;
};

Number add(const Number& arg0, const Number& arg1){
return std::visit(
overload{
[](int a, int b) -> Number{return add_(a, b);}
,[](float a, float b) -> Number{return add_(a, b);}
,[](auto& a, auto& b) -> Number{throw std::runtime_error("unsupported parameter combination");}
},
arg0, arg1
);
}

How to throw a C++ exception

Simple:

#include <stdexcept>

int compare( int a, int b ) {
if ( a < 0 || b < 0 ) {
throw std::invalid_argument( "received negative value" );
}
}

The Standard Library comes with a nice collection of built-in exception objects you can throw. Keep in mind that you should always throw by value and catch by reference:

try {
compare( -1, 3 );
}
catch( const std::invalid_argument& e ) {
// do stuff with exception...
}

You can have multiple catch() statements after each try, so you can handle different exception types separately if you want.

You can also re-throw exceptions:

catch( const std::invalid_argument& e ) {
// do something

// let someone higher up the call stack handle it if they want
throw;
}

And to catch exceptions regardless of type:

catch( ... ) { };

Is it safe to use c_str() as a parameter in std::exception?

std::exception does not have a contructor that takes a const char* or a std::string.

std::runtime_error (and its descendants) does have constructors for both. And yes, it is perfectly safe (well, provided that memory is not low) to pass the message.c_str() pointer to this constructor. std::runtime_error will copy the character data into its own internal memory, allowing message to be destroyed after the exception is thrown.

If you want to throw std::exception itself with a string message, you will have to derive a custom class from it and implement your own string buffer for what() to return a pointer to. In which case, you have to be careful not to return an invalid const char* pointer from what(). std::runtime_error handles that for you, so you should derive from that instead.

c++ exception : throwing std::string

Yes. std::exception is the base exception class in the C++ standard library. You may want to avoid using strings as exception classes because they themselves can throw an exception during use. If that happens, then where will you be?

boost has an excellent document on good style for exceptions and error handling. It's worth a read.

Passing message in std::exception from managed code to unmanaged

Following suggestion made by @Joe, I inherit from std::exception ...

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

private:
std::string msg_;
};

... and then ...

const std::string myExMsg = msclr::interop::marshal_as<std::string>(ex->Message);
throw InvokeException(myExMsg);

What is the proper way to raise exception and handle certain exception type in C++

You can have multiple catch statements, like this:

try {
execute(query);
}
catch (const my_custom_exception_type& e) {
}
catch (const std::runtime_error& e) {
}
catch (const std::exception& e) {
}
catch (...) {
// fallback - exception object is not any of the above types
}

Control will flow into the first catch block whose parameter type is compatible with the exception object type. If none match and there is no ... catch-all, the exception will propagate out of that try/catch block. A more precise explanation of the exact try/catch behavior can be found here:

When an exception of type E is thrown by any statement in compound-statement, it is matched against the types of the formal parameters T of each catch-clause in handler-seq, in the order in which the catch clauses are listed. The exception is a match if any of the following is true:

  • E and T are the same type (ignoring top-level cv-qualifiers on T)
  • T is an lvalue-reference to (possibly cv-qualified) E
  • T is an unambiguous public base class of E
  • T is a reference to an unambiguous public base class of E
  • T is (possibly cv-qualified) U or const U& (since C++14), and U is a pointer or pointer to member (since C++17) type, and E is also a pointer or pointer to member (since C++17) type that is implicitly convertible to U by one or more of

    • a standard pointer conversion other than one to a private, protected, or ambiguous base class
    • a qualification conversion
    • a function pointer conversion (since C++17)
  • T is a pointer or a pointer to member or a reference to a const pointer (since C++14), while E is std::nullptr_t.

You can also use RTTI to determine the type of e but avoid that if at all possible.



Related Topics



Leave a reply



Submit