此问题已在此处有答案:
Why does this work: returning C string literal from std::string function and calling c_str()(9个回答)
9年前关闭。
代码:
stringstream ss("012345678901234567890123456789012345678901234567890123456789");
有些文章说它是错误的,因为ss.str返回临时对象,并会在调用.c_str()之前析构;
const char* cstr2 = ss.str().c_str();
但我运行的例子,没有问题吗?如何理解?
3条答案
按热度按时间n6lpvg4x1#
但是我运行的例子,有问题吗?
从技术上讲,表达式中没有任何“立即”错误:
ss.str()
返回的临时(副本)对象将存在足够长的时间,以便您使用c_str()
获取底层的c字符串。但结果很可能是一个悬空指针:在表达式结束时,字符串对象可能已经被销毁了,因此底层内存可能会被释放(这在很大程度上取决于
std::basic_string
的实现)。因此,应该避免这种方法,因为不可能安全地使用结果指针。你应该做的是:
上面的代码不会给你带来任何麻烦,因为
str()
的返回值现在正在被复制/不再是临时的,并且对x.c_str()
的访问将给予你一个有效的指针。tzxcd3kk2#
又一个奇妙的C++地雷。
基本上,您的指针引用了一个内存块(C字符串),该内存块引用了在您进行双重修改时流中的任何内容的临时副本(字符串)。
String()返回一个临时对象。
临时对象的预期寿命相当短。或者有人立即引用它们(例如
string& s = ss.str()
),或者它们在它们出生的语句的末尾死亡。然而,编译器允许通过c_str()获得对同一内存块的引用,但这是间接的,因此它在编译器的雷达下飞行。真可惜。
所以你的指针在c_str得到它的时候确实是有效的,但是只要你在普通的老C中做了这样的事情:
因此,就在这条语句结束之后,c_str已经引用了str()返回的任何字符串的尸体。
现在,由于临时对象是在堆栈上分配的,您可能永远不会注意到这个问题。对象释放本身可能不会修改失效的字符串值,但是一旦编译器重用堆栈的这一部分,proverbial guru就需要考虑一些事情了。
3gtaxfhh3#
首先,重要的是要理解,尝试使用悬挂指针并不一定会以任何明显的方式失败。它可以看起来“工作”,就像它可以经常崩溃壮观。
其次,是的,该代码是无效的,你不应该这样做。stringstream的生存期并不重要,因为
std::stringstream::str()
返回 by value(即内部缓冲区的 * 副本 *),但在您可以使用其C字符串指针之前,您仍然会遇到该字符串超出范围的情况。