C++98 string concatenation with c_str() return

I wanted to create a custom exception by concatonating a string before returning it on what(). I am aware of other ways to achive the wanted result, i just want to undertand why the 3 following pieces of code are behaving differently.

class InvalidFormat : public std::exception
{
    private:
        std::string _exceptionValue;
    public:
        InvalidFormat(std::string str);
        const char *what() const throw();
};

InvalidFormat::InvalidFormat(std::string str) : _exceptionValue(str) {}

const char *InvalidFormat::what() const throw() {
return ("Format is invalid => " + _exceptionValue).c_str();}
//doesn't output anything
InvalidFormat::InvalidFormat(std::string str) : _exceptionValue(str) {}

const char *InvalidFormat::what() const throw() {
return std::string("Format is invalid => ").assign(_exceptionValue).c_str();}
//outputs random data
InvalidFormat::InvalidFormat(std::string str) : _exceptionValue("Format is invalid => " + str) {}

const char *InvalidFormat::what() const throw() {
return _exceptionValue.c_str();}
//outputs is correct

>Solution :

The following calls c_str() on a temporary std::string whose life ends after the full expression (at the ;):

return ("Format is invalid => " + _exceptionValue).c_str(); // UB-prone

When InvalidFormat::what() returns, the returned pointer points to memory freed and gone, which is undefined behaviour. This is no better:

return std::string("Format is invalid => ").assign_exceptionValue).c_str(); // UB-prone

You must store the result of the concatenation if you want to return a non-owning pointer to it:

InvalidFormat::InvalidFormat(std::string str)
    : _exceptionValue("Format is invalid => " + str)
{}

const char *InvalidFormat::what() const throw()
{
    return _exceptionValue.c_str(); // OK
}

Leave a Reply