从函数返回 const char*
Returning const char* from funciton
我有这个函数,我正在尝试 return 一个 const char*,但是当我尝试输出 returned 值时,我得到了垃圾值;
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.
}
当我尝试打印时:
catch (std::exception& e)
{
std::cout << e.what() << std::endl;
}
我明白了(每次都不同..):
▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌╢Pⁿש▌'
我做错了什么?
您正在 return 指向本地 std::string
对象的内部 char
数据的指针,该对象在函数退出时被销毁,因此 returned 指针悬空,指向无效内存。之后尝试访问数据是 未定义的行为。
通常,您有两种选择来解决这个问题:
return 一个 std::string
而不是 char*
指针。
动态分配 char
数据,然后让调用者在使用完后释放它。
但是,在这种情况下,您要覆盖 std::exception::what()
方法,因此这些选项都不可行。您需要做的是将 char
数据存储在派生 class 的 std::string
成员中,然后您可以 return 指向 char*
的指针它的数据,例如:
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();
}
如果您从 std::runtime_error
而不是直接从 std::exception
派生异常 class,这已经为您处理了。 std::runtime_error
在其构造函数中获取一个字符串,并将 what()
覆盖为 return 该字符串的数据。
问题 是 tmp
是函数 what
的局部变量,而您正在 return 指向该局部函数的内部指针大批。这是一个问题,因为一旦函数退出,local 就会被销毁。也就是说,你return的指针是一个悬挂指针。使用那个悬挂指针(你在写 std::cout << e.what() << std::endl;
时所做的)是 未定义的行为。
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.
所以您看到(也许看到)的输出是未定义行为的结果。正如我所说,不要依赖具有 UB 的程序的输出。程序可能会崩溃。
因此,使程序正确的第一步是删除 UB。 然后并且只有那时你可以开始对程序的输出进行推理。
1有关未定义行为的更准确的技术定义,请参阅 this 其中提到:没有对程序行为的限制.
我有这个函数,我正在尝试 return 一个 const char*,但是当我尝试输出 returned 值时,我得到了垃圾值;
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.
}
当我尝试打印时:
catch (std::exception& e)
{
std::cout << e.what() << std::endl;
}
我明白了(每次都不同..):
▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌╢Pⁿש▌'
我做错了什么?
您正在 return 指向本地 std::string
对象的内部 char
数据的指针,该对象在函数退出时被销毁,因此 returned 指针悬空,指向无效内存。之后尝试访问数据是 未定义的行为。
通常,您有两种选择来解决这个问题:
return 一个
std::string
而不是char*
指针。动态分配
char
数据,然后让调用者在使用完后释放它。
但是,在这种情况下,您要覆盖 std::exception::what()
方法,因此这些选项都不可行。您需要做的是将 char
数据存储在派生 class 的 std::string
成员中,然后您可以 return 指向 char*
的指针它的数据,例如:
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();
}
如果您从 std::runtime_error
而不是直接从 std::exception
派生异常 class,这已经为您处理了。 std::runtime_error
在其构造函数中获取一个字符串,并将 what()
覆盖为 return 该字符串的数据。
问题 是 tmp
是函数 what
的局部变量,而您正在 return 指向该局部函数的内部指针大批。这是一个问题,因为一旦函数退出,local 就会被销毁。也就是说,你return的指针是一个悬挂指针。使用那个悬挂指针(你在写 std::cout << e.what() << std::endl;
时所做的)是 未定义的行为。
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.
所以您看到(也许看到)的输出是未定义行为的结果。正如我所说,不要依赖具有 UB 的程序的输出。程序可能会崩溃。
因此,使程序正确的第一步是删除 UB。 然后并且只有那时你可以开始对程序的输出进行推理。
1有关未定义行为的更准确的技术定义,请参阅 this 其中提到:没有对程序行为的限制.