ようこそ ゲスト さん、新規登録(無料)して気になる疑問を解決しませんか?

質問

質問者:rotofrot ostringstreamではまりました
困り度:
  • 困っています
const char*を受け付ける関数に、文字列を組み立てて渡すために、
以下のようにしました。
しかし、結果何も出力されません。
どこがまずいのでしょうか?

std::ostringstream str_stream;
str_stream << "aiueo" << 33;

const char* c_str = str_stream.str().c_str();
std::cout << c_str << std::endl;
質問投稿日時:08/04/08 05:33
質問番号:3931440
この質問に対する回答は締め切られました。
最新から表示回答順に表示良回答のみ表示

回答

良回答20pt

回答者:AsanoNagi > std::string moji = str_stream.str();
> const char* c_str = moji.c_str();

この場合、moji が、最後まで生き残っていますから、moji.c_str() は有効なC文字列の先頭をポイントし続けます。

> const char* c_str = str_stream.str().c_str();

こちらの場合は、str_stream にある実体から、一度、std::string が生成されて、この行を抜けると破棄される。
その破棄されたオブジェクトが提供していたポインタを見ているので、それは保証されないというところです。

std::string は、C文字列を内部的に持っていて、それをもとにデータを加工しているような実装が普通には考えられます。
strstream も、内部的に、string を持っていて、それをもとにデータを加工しているような実装が普通には考えられます。
その場合、「破棄された」といっても、C文字列が入っているメモリそのもには、(再利用されるまで)そのまま残っているケースがあります。
との場合には、たまたま、「破棄された」C文字列のポインタが、もともと、文字列が入っていた領域をポイントしていて、そこには、まだ、以前の文字列が残っているという可能性もあります。

この場合に、たまたま動いているように見えるということですね。

上記のような実装は、必須ではないですし、もしかしたら、破棄されるときにデータ領域をちゃんと消していく実装もあるかもしれません。
その場合は、動いていないように見えるということになるのでしょう。
種類:回答
どんな人:一般人
自信:参考意見
回答日時:08/04/08 09:11
回答番号:No.5
この回答へのお礼ありがとうございます。
からくりがよく理解できました。

回答

良回答10pt

回答者:koko_u_ MSDN で c_str() の戻り値を見ると

------- 引用 ------
The pointer value is not valid after calling a non-const function, including the destructor, in the basic_string class on the object.
-------------------

と書いてあるから、str_stream.str() で作成された一時オブジェクトが破棄された後、c_str の値は保証されないようですね。

単に string("aiueo").c_str() としてもやはり NG みたい。これはハマリそう。
種類:アドバイス
どんな人:一般人
自信:参考意見
回答日時:08/04/08 08:53
回答番号:No.4
この回答へのお礼引用までしていただいてありがとうございます。
理解できました。

回答

 

回答者:HowOver あーなるほどーそうでしたか
私一般人なのでただ見てるだけのつもりだったんですけど
全角に気づいたので突っ込んでみただけなのでなんともですけど、

こちらでは全角取り除けば"aiueo33"って出ますよ?
素人なので不正確になってしまいますけど私のコンパイラは
gcc ver3.2 か 3.4.2
みたいですけど。
そちらは何をお使いで?
種類:補足要求
どんな人:一般人
自信:参考意見
回答日時:08/04/08 07:12
回答番号:No.3
この回答への補足ありがとうございます。
失礼しました。
こちらの環境はVC++2008 Express Editionです。
cygwinでgcc 3.4.4で同じコードをコンパイルして動かすと
問題なく動きました。
VCのバグか何かなのでしょうか…
それともgccではたまたま動いているだけなのでしょうか。
この回答へのお礼この回答にお礼をつける(質問者のみ)

回答

 

回答者:episteme > const char* c_str = str_stream.str().c_str();

str_stream.str() で一時的に作られた string の寿命が
極めて短く、c_str() が評価された直後にデストラクト
されているのでしょうね。
種類:回答
どんな人:専門家
自信:自信あり
回答日時:08/04/08 06:46
回答番号:No.2
この回答への補足回答ありがとうございます。
なるほど、つまり、

const char* c_str = str_stream.str().c_str();

の行が終わった時点でstr()によって取得したstringオブジェクトは
破棄されてしまうというわけですか。

疑問があるのですが、これはC++の標準の動きなのでしょうか?
というのも、同じコードcygwinでg++でコンパイルしたら問題なく
動作しました。
書き忘れていたのですが、質問時のコードはVC++2008 Expressでコンパイルしました。
VC++9.0のバグ、ということはないでしょうか?
VC++9.0とg++ではどちらが正しい動きをしているのでしょうか?
この回答へのお礼この回答にお礼をつける(質問者のみ)

回答

 

回答者:HowOver "aiueo" << 33;
"と<<
のあいだに
全角スペースはいっとりまっせ〜
これははまるは
そのまま貼り付けなかったら解決しませんでしたね
種類:アドバイス
どんな人:一般人
自信:参考意見
回答日時:08/04/08 06:07
回答番号:No.1
この回答への補足すみません。全角スペースはタイプミスです。
手元のソースでは普通のスペースになっています。
コンパイルは通ることを確認しています。
失礼しました。
全角スペース問題ではないようです。
よくわからないのは、以下のようにするとうまく動くことです。
std::string moji = str_stream.str();
const char* c_str = moji.c_str();

どうして、
const char* c_str = str_stream.str().c_str();
と一行でまとめて書くとうまくいかないのでしょうか。
この回答へのお礼この回答にお礼をつける(質問者のみ)
最新から表示回答順に表示良回答のみ表示