c++ 是否存在将stringstream.str().c_str()问题?[副本]

v6ylcynt  于 2023-05-19  发布在  其他
关注(0)|答案(3)|浏览(144)

此问题已在此处有答案

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();

但我运行的例子,没有问题吗?如何理解?

n6lpvg4x

n6lpvg4x1#

但是我运行的例子,有问题吗?
从技术上讲,表达式中没有任何“立即”错误:

const char* cstr2 = ss.str().c_str();

ss.str()返回的临时(副本)对象将存在足够长的时间,以便您使用c_str()获取底层的c字符串。

但结果很可能是一个悬空指针:在表达式结束时,字符串对象可能已经被销毁了,因此底层内存可能会被释放(这在很大程度上取决于std::basic_string的实现)。

因此,应该避免这种方法,因为不可能安全地使用结果指针。你应该做的是:

auto x = ss.str();
const char* cstr2 = x.c_str();

上面的代码不会给你带来任何麻烦,因为str()的返回值现在正在被复制/不再是临时的,并且对x.c_str()的访问将给予你一个有效的指针。

tzxcd3kk

tzxcd3kk2#

又一个奇妙的C++地雷。
基本上,您的指针引用了一个内存块(C字符串),该内存块引用了在您进行双重修改时流中的任何内容的临时副本(字符串)。
String()返回一个临时对象。
临时对象的预期寿命相当短。或者有人立即引用它们(例如string& s = ss.str()),或者它们在它们出生的语句的末尾死亡。
然而,编译器允许通过c_str()获得对同一内存块的引用,但这是间接的,因此它在编译器的雷达下飞行。真可惜。
所以你的指针在c_str得到它的时候确实是有效的,但是只要你在普通的老C中做了这样的事情:

const char * cstr2;
{
    char ss_str[100];            // str() return value is dynamically created
    char * c_str = &ss_str_[10]; // c_str() takes a reference to some part of it
    cstr2 = c_str;               // cstr2 takes an indirect reference to str() ret. val.
}                                // compiler pulls the plug on str() ret. val.

因此,就在这条语句结束之后,c_str已经引用了str()返回的任何字符串的尸体。
现在,由于临时对象是在堆栈上分配的,您可能永远不会注意到这个问题。对象释放本身可能不会修改失效的字符串值,但是一旦编译器重用堆栈的这一部分,proverbial guru就需要考虑一些事情了。

3gtaxfhh

3gtaxfhh3#

首先,重要的是要理解,尝试使用悬挂指针并不一定会以任何明显的方式失败。它可以看起来“工作”,就像它可以经常崩溃壮观。
其次,是的,该代码是无效的,你不应该这样做。stringstream的生存期并不重要,因为std::stringstream::str()返回 by value(即内部缓冲区的 * 副本 *),但在您可以使用其C字符串指针之前,您仍然会遇到该字符串超出范围的情况。

相关问题