stringstream、string 和 char* 转换混淆

2021-12-21 00:00:00 string memory c++ stringstream

我的问题可以归结为,从 stringstream.str().c_str() 返回的字符串在内存中的位置,为什么不能分配给 const char*?

My question can be boiled down to, where does the string returned from stringstream.str().c_str() live in memory, and why can't it be assigned to a const char*?

这个代码示例比我能解释的更好

This code example will explain it better than I can

#include <string>
#include <sstream>
#include <iostream>

using namespace std;

int main()
{
    stringstream ss("this is a string
");

    string str(ss.str());

    const char* cstr1 = str.c_str();

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

    cout << cstr1   // Prints correctly
        << cstr2;   // ERROR, prints out garbage

    system("PAUSE");

    return 0;
}

假设 stringstream.str().c_str() 可以分配给 const char* 导致了一个错误,我花了一段时间才找到.

The assumption that stringstream.str().c_str() could be assigned to a const char* led to a bug that took me a while to track down.

对于加分,谁能解释为什么用

For bonus points, can anyone explain why replacing the cout statement with

cout << cstr            // Prints correctly
    << ss.str().c_str() // Prints correctly
    << cstr2;           // Prints correctly (???)

正确打印字符串?

我正在 Visual Studio 2008 中编译.

I'm compiling in Visual Studio 2008.

推荐答案

stringstream.str() 返回在完整表达式结束时销毁的临时字符串对象.如果你从中得到一个指向 C 字符串的指针 (stringstream.str().c_str()),它将指向一个在语句结束处被删除的字符串.这就是为什么您的代码打印垃圾的原因.

stringstream.str() returns a temporary string object that's destroyed at the end of the full expression. If you get a pointer to a C string from that (stringstream.str().c_str()), it will point to a string which is deleted where the statement ends. That's why your code prints garbage.

您可以将该临时字符串对象复制到某个其他字符串对象并从该对象中获取 C 字符串:

You could copy that temporary string object to some other string object and take the C string from that one:

const std::string tmp = stringstream.str();
const char* cstr = tmp.c_str();

请注意,我创建了临时字符串 const,因为对它的任何更改都可能导致它重新分配,从而使 cstr 无效.因此,完全不存储对 str() 的调用结果并仅在完整表达式结束之前使用 cstr 更安全:

Note that I made the temporary string const, because any changes to it might cause it to re-allocate and thus render cstr invalid. It is therefor safer to not to store the result of the call to str() at all and use cstr only until the end of the full expression:

use_c_str( stringstream.str().c_str() );

当然,后者可能并不容易,复制可能太昂贵了.您可以做的是将临时对象绑定到 const 引用.这会将其生命周期延长到引用的生命周期:

Of course, the latter might not be easy and copying might be too expensive. What you can do instead is to bind the temporary to a const reference. This will extend its lifetime to the lifetime of the reference:

{
  const std::string& tmp = stringstream.str();   
  const char* cstr = tmp.c_str();
}

IMO 这是最好的解决方案.不幸的是,它不是很出名.

IMO that's the best solution. Unfortunately it's not very well known.

相关文章