代码:
stringstream ss("012345678901234567890123456789012345678901234567890123456789");
Run Code Online (Sandbox Code Playgroud)
一些文章说由于ss.str返回临时对象而导致后续使用是错误的,并且在调用之前会被破坏.c_str();
const char* cstr2 = ss.str().c_str();
Run Code Online (Sandbox Code Playgroud)
但我运行的例子,没有问题?如何理解?
但我运行的例子,没有问题?
事实上,表达式没有错:
const char* cstr2 = ss.str().c_str();
Run Code Online (Sandbox Code Playgroud)
返回的临时(复制)对象ss.str()将活得足够长,以便让你获得底层的c-string c_str().
当然,在表达式结束时,您将拥有一个const char指向可能已释放的对象的指针(这在很大程度上取决于std::basic_string实现).
因此,这可能不是一个好主意.你应该做的是:
auto x = ss.str();
const char* cstr2 = x.c_str();
Run Code Online (Sandbox Code Playgroud)
上面的代码不会给你带来任何麻烦,因为str()现在正在复制/不再是临时的返回值,并且访问x.c_str()将为您提供有效的指针.
又一个美妙的 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.
Run Code Online (Sandbox Code Playgroud)
因此,就在这个语句结束之后,c_str 已经在引用 str() 返回的任何字符串的尸体。
现在由于临时对象是在堆栈上分配的,您可能永远不会注意到这个问题。对象释放本身可能不会修改已失效的字符串值,但是一旦编译器将重用这一位堆栈,众所周知的大师就会有一些东西可以沉思。
首先,重要的是要理解尝试使用悬空指针并不能保证以任何明显的方式失败。它看起来“工作”的频率和它崩溃的频率一样高。
其次,是的,该代码无效,您不应该这样做。stringstream 的生命周期并不重要,因为按值std::stringstream::str()返回(即内部缓冲区的副本),但在使用其 C 字符串指针之前,您仍然会遇到该字符串超出范围的情况。
| 归档时间: |
|
| 查看次数: |
13484 次 |
| 最近记录: |