3

I am changing some code in a legacy code base. Inside this code there is an often repeated pattern that looks like the following:

std::stringstream ss;
ss << ...;
throw MyCustomException(ss.str());

Since I am modifying the code anyways I wanted to make something like the following:

throw MyCustomException() << ...;

effectively removing the need for the std::stringstream.

I found a solution:

struct MyCustomException: public std::runtime_error
{
    MyCustomException(const std::string& what_arg="")
    : std::runtime_error(what_arg)
    {
    }

#if 0
    template<typename T>
    friend
    MyCustomException operator<<(MyCustomException e, const T& obj)
    {
        std::stringstream ss;
        ss << e.what();
        ss << obj;
        return MyCustomException(ss.str());
    }
#else
    template<typename T>
    MyCustomException operator<<(const T& obj)
    {
        std::stringstream ss;
        ss << what();
        ss << obj;
        return MyCustomException(ss.str());
    }
#endif
};

Both solutions (#if ... #endif) work, but since everything is by value, a lot of copies of the exception object are created before it is thrown. Changing the signature to MyCustomException& e produces a ton of compile time errors (why?).

The whole problem is further complicated by the fact that I am bound to an old GCC revision that only supports C++03. So no fancy C++1[147] stuff here!

Is there a better way to make my desired functionality (throw MyCustomException() << ...;) work without the creation of the many temporary copies when throwing an exception?

1 Answer 1

1

[S]ince everything is by value, a lot of copies of the exception object are created before it is thrown

If exceptions are exceptional (as they should), the run-time lost should not be something you care about. Furthermore, copy elision might save your day. Profile and conclude.

That being said, you could remove half of the alleged copies by taking a const-ref:

struct MyCustomException: public std::runtime_error
{
    MyCustomException(const std::string& what_arg="")
    : std::runtime_error(what_arg)
    {}

    template<typename T>
    friend
    MyCustomException operator<<(MyCustomException const& e, T const& obj)
    {
        std::stringstream ss;
        ss << e.what();
        ss << obj;
        return MyCustomException(ss.str());
    }
};
Sign up to request clarification or add additional context in comments.

1 Comment

strange that I didn't think about the const reference thing :/ Unfortunately I still get the same amount of copies as before with friend ... const MyCustomException&. That's maybe even stranger.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.