I was trying to come up with some design to subclass built-in exceptions.
For simplest case I used something like this:
class SimpleCustomException : public std::runtime_error
{
public:
using std::runtime_error::runtime_error;
};
Source: How to inherit from std::runtime_error?
which, from my understanding, should work, as it is basically std::runtime_error in disguise.
But, if I wish to pass some additional data, say std::string, things get more complicated because exception should be copyable and at the same time it must not throw during stack unwinding because program will be terminated. So generic string is no-good because it may throw std::bad_alloc while copying.
So I came up with something simple like presented below. And my understanding is like this:
Constructor for this exception will attempt to create std::string through shared pointer. If this fails just nullptr is assigned as a fallback. Otherwise we have heap allocated data that is not copied (only pointer is) and it will not cause memory leak because it is reference counted.
#include <iostream>
#include <string>
#include <memory>
class CustomException : public std::runtime_error
{
public:
CustomException(const std::string &what, const std::string &err_data) noexcept
: std::runtime_error(what)
{
/* We try to allocate the data, as fallback just pass nullptr */
try {
this->error_data = std::make_shared<std::string>(err_data);
} catch (const std::bad_alloc &e) {
this->error_data = nullptr;
}
}
std::shared_ptr<std::string> what_data() const noexcept
{
return error_data;
}
private:
std::shared_ptr<std::string> error_data;
};
int main()
{
try {
throw CustomException("HELLO", "WORLD");
} catch (const CustomException &e) {
std::string message = e.what();
std::string extra_data;
if (e.what_data()) {
extra_data = *e.what_data();
}
std::cout << "Caught exception with message: " << message << std::endl;
std::cout << "And extra data: " << extra_data << std::endl;
}
return 0;
}
Is this solution actually safe? Can it be done in some better way?
-
1\$\begingroup\$ This is more of a StackOverflow question than a code review request. Code review requires a real project, not hypothetical or theoretical code, because real engineering questions only make sense with real engineering context. This design may be perfect and awesome in some contexts, and absolutely terrible in others. The only answer to your questions a competent reviewer can give is: "maybe!" or "it depends." \$\endgroup\$indi– indi2025年02月20日 20:35:49 +00:00Commented Feb 20 at 20:35
-
\$\begingroup\$ Alright, thank You for feedback. I will repost this at StackOverflow. \$\endgroup\$Jakub– Jakub2025年02月21日 06:50:54 +00:00Commented Feb 21 at 6:50
1 Answer 1
You don't need to do wrap the body of the constructor in try ... catch ..., just let std::bad_alloc escape, like std::runtime_error::runtime_error does.
At the point where you are constructing a CustomException, you aren't unwinding the stack. You are about to unwind the stack, once the exception is constructed.
Holding a shared ptr is correct, as copying the exception should be noexcept.
-
\$\begingroup\$ Thank You. Yea I guess letting the exception escape makes more sense, otherwise I am hiding an issue. Also thank You for confirming this approach is correct \$\endgroup\$Jakub– Jakub2025年02月21日 13:02:18 +00:00Commented Feb 21 at 13:02
Explore related questions
See similar questions with these tags.