从函数返回 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 其中提到:没有对程序行为的限制.