I have this function, where I'm trying to return a const char*, but when I try to output the returned value, I get garbage value;
virtual const char* what() const noexcept
{
std::stringstream s;
if(m_id > -1)
s << m_message << " with id " << m_id << " does not exist";
else
s << m_message << " with name " << m_name << " does not exist";
//until now it works fine
std::string tmp = s.str();
const char* temp = tmp.c_str();
return temp; //after I execute this command, the value is deleted.
}
when I try to print:
catch (std::exception& e)
{
std::cout << e.what() << std::endl;
}
I get this (different every time..) :
▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌╢Pⁿש▌'
What am I doing wrong?
CodePudding user response:
You are returning a pointer to the internal char
data of a local std::string
object that is destroyed when the function exits, thus the returned pointer is left dangling, pointing at invalid memory. Trying to access the data afterwards is undefined behavior.
Normally, you would have two choices to fix that:
return a
std::string
instead of achar*
pointer.allocate the
char
data dynamically, and then make the caller free it when done using it.
However, in this case, you are overriding the std::exception::what()
method, so neither of those options are viable. What you will have to do instead is store your char
data in a std::string
member of your derived class, and then you can return a char*
pointer to its data, eg:
private:
std::string m_what;
myException::myException(...)
{
...
std::stringstream s;
if (m_id > -1)
s << m_message << " with id " << m_id << " does not exist";
else
s << m_message << " with name " << m_name << " does not exist";
m_what = s.str();
}
virtual const char* what() const noexcept
{
return m_what.c_str();
}
If you derive your exception class from std::runtime_error
instead of std::exception
directly, this is already handled for you. std::runtime_error
takes a string in its constructor, and overrides what()
to return that string's data.
CodePudding user response:
The problem is that tmp
is local to the function what
and you're returning a pointer to that local's internal array. This is a problem because the local will be destroyed once the function exits. That is, the pointer that you return is a dangling pointer. Using that dangling pointer(which you do when you wrote std::cout << e.what() << std::endl;
) is undefined behavior.
Undefined behavior means anything1 can happen including but not limited to the program giving your expected output. But never rely(or make conclusions based) on the output of a program that has undefined behavior.
So the output that you're seeing(maybe seeing) is a result of undefined behavior. And as i said don't rely on the output of a program that has UB. The program may just crash.
So the first step to make the program correct would be to remove UB. Then and only then you can start reasoning about the output of the program.
1For a more technically accurate definition of undefined behavior see this where it is mentioned that: there are no restrictions on the behavior of the program.