17

I'm not sure that my custom exception approach is correct. What I want to do is to throw exceptions with custom messages but it seems that I created a memory leak...

class LoadException: public std::exception {
private:
    const char* message;
public:
    LoadException(const std::string message);
    virtual const char* what() const throw();
};


LoadException::LoadException(const std::string message) {
    char* characters = new char[message.size() + 1];
    std::copy(message.begin(), message.end(), characters);
    characters[message.size()] = '\0';
    this->message = characters;
}

I use it as follows:

void array_type_guard(Local<Value> obj, const std::string path) {
    if (!obj->IsArray()) {
        throw LoadException(path + " is not an array");
    }
}

try {
    objects = load_objects();
} catch (std::exception& e) {
    ThrowException(Exception::TypeError(String::New(e.what())));
    return scope.Close(Undefined());
}

I afraid that the array created in constructor is never deleted. But I'm not sure how to delete it - should I add destructor or maybe use completely different approach?

Update:

I've actually tried to use the string class as follows:

class LoadException: public std::exception {
private:
    const char* msg;
public:
    LoadException(const std::string message);
    virtual const char* what() const throw();
};

LoadException::LoadException(const std::string message) {
    msg = message.c_str();
}

const char* LoadException::what() const throw() {
    return msg;
}

But cannot get the error message then - some random output is displayed when I print the "what()".

Alex Netkachov
  • 13,172
  • 6
  • 53
  • 85

3 Answers3

38

How about
throw std::runtime_error("My very own message");

MonoThreaded
  • 11,429
  • 12
  • 71
  • 102
24

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

Jonas
  • 1,356
  • 2
  • 11
  • 16
NG.
  • 22,560
  • 5
  • 55
  • 61
  • 3
    Would be better to pass by non-const value and move construct `message_` – Captain Obvlious Jul 03 '13 at 03:02
  • Thanks. It works this way, but I do not know why... It looks like the string is copied to the exception object. Am I right? – Alex Netkachov Jul 03 '13 at 03:05
  • It works because `string` allocates and deallocates buffer on it's own. It does exactly the same as you did, but additionally it `delete`s allocated memory in it's destructor. – j_kubik Jul 03 '13 at 03:27
  • When the exception goes out of scope, the members of the exception have their destructor called. The string class takes care of managing its own buffer, so it cleans up after itself when its destructor is called, and this happens when the LoadException goes out of scope. – NG. Jul 03 '13 at 16:26
  • You actually also need to specify an override `LoadException::~LoadException() throw() {}`, otherwise you have a looser throw specifier error. – Halfgaar Oct 21 '13 at 17:50
2

In the constructor I have

Printer::Printer(boost::asio::io_service& io, unsigned int interval) {
    if (interval < 1) {
        throw std::runtime_error("Interval can't be less than one second");
    }
}

And when creating the object

try {
    Printer p{io, 0};
} catch (std::exception& e) {
    std::cerr << e.what() << std::endl;
}

the program will exit with the message thrown.

kometen
  • 6,536
  • 6
  • 41
  • 51