是否会出现问题stringstream.str()。c_str()? [重复]

问题描述 投票:1回答:3

代码:

stringstream ss("012345678901234567890123456789012345678901234567890123456789");  

一些文章说由于ss.str返回临时对象而导致后续使用是错误的,并且在调用之前会被破坏.c_str();

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

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

c++ stringstream
3个回答
5
投票

但我运行的例子,没有问题?

事实上,表达式没有错:

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

ss.str()返回的临时(复制)对象将活得足够长,以便让你用c_str()获取底层的c-string。

当然,在表达式结束时,你将有一个const char指向一个可能被释放的对象(这在很大程度上取决于std::basic_string实现)。

因此,这可能不是一个好主意。你应该做的是:

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

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


4
投票

首先,重要的是要理解尝试使用悬空指针并不能保证以任何明显的方式失败。它似乎经常“工作”,因为它可以惊人地崩溃。

其次,是的,该代码无效,您不应该这样做。 stringstream的生命周期并不重要,因为std::stringstream::str()按值返回(即内部缓冲区的副本),但是在你可以使用它的C字符串指针之前,你仍然需要超出范围。


3
投票

又一个美妙的C ++地雷。

基本上,您的指针引用一个内存块(C字符串),该内存块引用了您执行双重操作时流中任何内容的临时副本(字符串)。

str()返回一个临时对象。

临时物体的预期寿命相当短。有人要么立即引用它们(例如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就会有一些东西需要冥想。

© www.soinside.com 2019 - 2024. All rights reserved.