1. ホーム
  2. c++

[解決済み] stringstream, string, char* 変換の混乱

2022-05-31 17:28:39

質問

私の質問は、以下のように要約できます。 stringstream.str().c_str() から返された文字列はメモリ上のどこにあるのか、そしてなぜそれが const char* ?

このコード例は、私よりもうまく説明してくれるでしょう。

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

using namespace std;

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

    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* はバグを引き起こし、それを追跡するのにしばらくかかりました。

ボーナスポイントとして、なぜ cout という文に置き換えた理由を説明できる人はいますか?

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

は文字列を正しく表示しますか?

Visual Studio 2008でコンパイルしています。

どのように解決するのですか?

stringstream.str() は一時的な文字列オブジェクトを返し、完全な式の終了時に破棄されます。もし、そこからCの文字列へのポインタを得ると( stringstream.str().c_str() ) から C の文字列へのポインタを得ると、それは文が終わったところで削除される文字列を指すことになります。これが、あなたのコードがゴミを表示する理由です。

その一時的な文字列オブジェクトを他の文字列オブジェクトにコピーして、そこからCの文字列を取り出すことができます。

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

なお、一時的な文字列を const に変更すると再割り当てされる可能性があるためです。 cstr を無効にしてしまうからです。の呼び出しの結果は保存しない方が安全です。 str() を呼び出した結果を全く保存せず cstr を使い、完全な式の終わりまでしか使いません。

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

もちろん、後者は簡単ではないかもしれませんし、コピーにはコストがかかりすぎるかもしれません。その代わりにできることは、一時的なものを const 参照にバインドすることです。これによって、その寿命は参照の寿命まで延長されます。

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

IMOはそれが最良の解決策だと考えています。残念ながらあまり知られていないのですが。