超出范围的问题?

myb*_*ess 1 c++ stringstream lifetime

我使用的框架已经在 CentOS 7 上运行了多年。我们正在将其迁移到 RHEL 8,但一些单元测试失败了。其中一个特别涉及从 std::runtime_error 上的 What() 返回垃圾。我创建了一个非常简单的例子来重复这个问题。它适用于 CentOS7,但不适用于 RHEL 8。代码如下:

#include <sstream>
#include <iostream>

const char * getString() {

    std::ostringstream oss;
    oss << "some stuff to return" << std::endl;

    std::cout << "value to return: " << oss.str().c_str() << std::endl;

    return oss.str().c_str();
}

int
main(int argc, char ** argv) {

    std::string value = getString();
    std::cout << "value returned: " << value << std::endl;

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

CentOS7 的输出是:

[user@localhost ~]$ ./a.out
value to return: some stuff to return

value returned: some stuff to return
Run Code Online (Sandbox Code Playgroud)

而 RHEL8 上的输出是:

[user@localhost badoverload]$ ./a.out
value to return: some stuff to return

value returned: `
Run Code Online (Sandbox Code Playgroud)

该值是否超出范围且不可用,但 CentOS 7 中的内存恰好未受影响?还是有其他事情发生?

Ted*_*gmo 11

getString()在这里返回一个悬空指针:

return oss.str().c_str();
Run Code Online (Sandbox Code Playgroud)

返回std::string的 bystr()是临时的,当它超出整个表达式末尾的范围时,它就会被销毁。

所以,当你这样做...

std::string value = getString();
Run Code Online (Sandbox Code Playgroud)

...从悬空指针读取,整个程序具有未定义的行为

只需返回 astd::string而不是 a const char*

return oss.str().c_str();
Run Code Online (Sandbox Code Playgroud)

  • @mybodycravesbutterygoodness `std::runtime_error` 已经具有字符串存储空间,并且可以从 `std::string` 构造。它的“what()”函数只是返回一个指向异常内部存储内容的指针。_“我确实在派生异常中创建了本地 std::string 属性”_ - 如果您从 `runtime_error` 派生,则不需要。[示例](https://godbolt.org/z/qsocqaTMs) (4认同)
  • @mybodycravesbutterygoodness 谁负责释放“const char*”? (3认同)
  • 换句话说,在调用“runtime_error”的继承构造函数时构建所需的字符串,而不是在重写的“what()”方法中。([演示](https://godbolt.org/z/Y6G3erzd7)) (3认同)