• ベストアンサー

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;

質問者が選んだベストアンサー

  • ベストアンサー
回答No.5

> 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文字列のポインタが、もともと、文字列が入っていた領域をポイントしていて、そこには、まだ、以前の文字列が残っているという可能性もあります。 この場合に、たまたま動いているように見えるということですね。 上記のような実装は、必須ではないですし、もしかしたら、破棄されるときにデータ領域をちゃんと消していく実装もあるかもしれません。 その場合は、動いていないように見えるということになるのでしょう。

rotofrot
質問者

お礼

ありがとうございます。 からくりがよく理解できました。

その他の回答 (4)

  • koko_u_
  • ベストアンサー率18% (459/2509)
回答No.4

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 みたい。これはハマリそう。

rotofrot
質問者

お礼

引用までしていただいてありがとうございます。 理解できました。

  • HowOver
  • ベストアンサー率30% (17/56)
回答No.3

あーなるほどーそうでしたか 私一般人なのでただ見てるだけのつもりだったんですけど 全角に気づいたので突っ込んでみただけなのでなんともですけど、 こちらでは全角取り除けば"aiueo33"って出ますよ? 素人なので不正確になってしまいますけど私のコンパイラは gcc ver3.2 か 3.4.2 みたいですけど。 そちらは何をお使いで?

rotofrot
質問者

補足

ありがとうございます。 失礼しました。 こちらの環境はVC++2008 Express Editionです。 cygwinでgcc 3.4.4で同じコードをコンパイルして動かすと 問題なく動きました。 VCのバグか何かなのでしょうか… それともgccではたまたま動いているだけなのでしょうか。

回答No.2

> const char* c_str = str_stream.str().c_str(); str_stream.str() で一時的に作られた string の寿命が 極めて短く、c_str() が評価された直後にデストラクト されているのでしょうね。

rotofrot
質問者

補足

回答ありがとうございます。 なるほど、つまり、 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
  • ベストアンサー率30% (17/56)
回答No.1

"aiueo" << 33; "と<< のあいだに 全角スペースはいっとりまっせ~ これははまるは そのまま貼り付けなかったら解決しませんでしたね

rotofrot
質問者

補足

すみません。全角スペースはタイプミスです。 手元のソースでは普通のスペースになっています。 コンパイルは通ることを確認しています。 失礼しました。 全角スペース問題ではないようです。 よくわからないのは、以下のようにするとうまく動くことです。 std::string moji = str_stream.str(); const char* c_str = moji.c_str(); どうして、 const char* c_str = str_stream.str().c_str(); と一行でまとめて書くとうまくいかないのでしょうか。

関連するQ&A

  • c++11での文字列リテラルの特殊化について

    c++11言語でのテンプレート部分特殊化についての質問です。 コメントアウト部分は出力結果です template<class T> struct VT { static const int type = 1;}; template<class T,int N> struct VT< T[N] > { static const int type = 2;}; template<class T,int N> struct VT< const T[N] > { static const int type = 3;}; template<class T> struct VT< T* > { static const int type = 4;}; template<class T> struct VT< const T*const > { static const int type = 5;}; #include<iostream> #include<typeinfo> int main(){ std::cout<<"A:"<< VT< char >::type << std::endl; // A:1 std::cout<<"B:"<< VT< char[10] >::type << std::endl; // B:2 std::cout<<"C:"<< VT< char* >::type << std::endl; // C:4 std::cout<<"D:"<< VT< char const [1] >::type << std::endl; // D:3 std::cout<<"E:"<< VT< decltype("") >::type << std::endl; // E:1 std::cout<<"G:"<< typeid( char const [1] ).name() << std::endl;// G:char const [1] std::cout<<"H:"<< typeid( "" ).name() << std::endl;// H:char const [1] } 型名を直接記述したD,G、文字列リテラルを記述したE,H。 コンパイラ毎の差はあれど、GとHの型名は同じものが表示されます。 ですが、[D:3] [E:1]と値は違い、別の特殊化テンプレートが使われています。 この部分が分かりません。 また、配列リテラル、文字列リテラルに対し部分特殊化テンプレートを宣言する方法などありましたら、ご教示お願いします。

  • プログラムの動作

    10文字をスキップするプログラムなのですが、どのようにスキップしているのかわからないので教えてください。 下にソースコードを書きます。 #include <iostream> using namespace std; //10文字をスキップする istream &skipchar(istream &stream) { int i; char c; for(i=0; i<10; i++)stream >> c; return stream; } int main() { char str[80]; cout << "いくつかの文字を入力する:"; cin >> skipchar >> str; cout << str << endl; return 0; } よろしくおねがいします。

  • std::stringクラスのc_str()で取得した文字列をいじることは可能ですか?

    c++で、以下のようなコードは問題ないでしょうか? // chrの中身の小文字を大文字にする void func(char* chr); std::string str("aaa"); const char* str_p = std.c_str(); func((char*)str_p); ←これは大丈夫ですか? //このあとstrに対して文字列を追加したりいろいろ処理する。 このようにc_strで取得したconst char*をconstをはずして 強引にいじくることは問題ないでしょうか?

  • プログラムの動作の仕方

    この下のプログラムは、WRITE <ファイル名>をコマンド行で入力すると、動作するプログラムなのですが、この通りにWRITE <test>としてもできません。 やり方を教えてください. #include <iostream> #include <fstream> using namespace std; int main(int argc,char *argv[]) { if(argc!=2){ cout << "使い方:WRITE<ファイル名>" << endl; return 1; } ofstream out(argv[1]); //出力ファイル if(!out){ cout << "出力ファイルが開けません" << endl; return 1; } char str[80]; cout << "文字列をディスクに書き込み、$で停止します" << endl; do{ cout << ": "; cin >> str; out << str << endl; }while(*str!='$'); out.close(); return 0; } お願いします。

  • C/C++関数間でのStringクラスの扱い

    以下のようなコードを実行してみましたが思い通りに動いてくれません. "sample"という文字列がstrへとコピーされると思ったのですが. stringクラスのc_str()メソッドはconst char*だと言っているので無理矢理キャストしたのが原因でしょうか.stringクラスは記憶領域を自動で変更してくれるのではないのですか.それともこの挙動は仕様ですか. -------- 以下コード -------- #include <iostream> #include <string> using namespace std; int func(char *); int main(void) {     string str("");     func((char *)str.c_str());     cout << "String: " << str << endl;     return EXIT_SUCCESS; } int func(char *buf) {     buf = "sample";     return 0; } -------- 以上コード --------

  • constについて

    void SMonster::walk(const std::string& str){ std::cout<<"てきてき"<<std::endl; power--; } のconst std::string& strと書くと効率がよいと本に書いてあったのですが、なぜ効率がいいのでしょうか?

  • C++での戻り値について

    C++で以下のソースを書きました。 どうしてaaaは問題ないのにbbbはだめなのかがわかりません。 どちらも、func1()、func2()で設定した文字列・vectorのポインタを返したいです。 int main() { const char* aaa = NULL; std::vector<const char*>* bbb = NULL; aaa = func1(); bbb = func2(); } const char* func1() { const char* str = NULL; str = "test"; return str; } std::vector<const char*>* func2() { std::vector<const char*>* str2 = NULL; str2->push_back("test2"); str2->push_back("test3"); return str2; } 現在必要に迫られてC++勉強中です。よろしくお願いいたします。

  • 配列の練習問題

    #include<iostream> using namespace std; //count関数の宣言 int count(char str[], char ch); int main() { char str[100]; char ch; cout << "文字列を入力して下さい。\n"; cin >> str; cout << "文字列から探す文字を入力して下さい。\n"; cin >> ch; int c = count(str, ch); cout << str << "の中に" << ch << "は" << c << "個あります。\n"; return 0; } //count関数の定義 int count(char str[], char ch) { int i = 0; int c = 0; while (str[i]) { if (str[i] == ch) c++; i++; } return c; } こんにちは。 この問題の解答のプログラムの意味がイマイチ解らないので良かったら教えて下さい。 確認がてらに質問します。 よろしくお願いします。

  • C++言語で文字列を出力するにはどうしたら良いですか。

    C++言語で文字列を出力するにはどうしたら良いですか。 今、ポインタの勉強中ですが、ポインタの使い方がよく分からないです。 次のコードで ---------- one two three ---------- を出力したいのですが、nしか出力できません。 どうやらoneのnしか出力できません。 どのようなコードを書いたら解決できますでしょうか。 ------------------------------------------- #include<iostream> using namespace std; char name[3][10]={{"one"},{"two"},{"three"}}; char f(const char *name,int i){ return name[i]; } int main(){ cout << f(name[0],1) << endl; } -------------------------------------------

  • C++文字列の挿入、結合のコードについて

    実行結果のような出力をするためには、 以下のコードの(ウ)(エ)(オ)の部分には何を入れたらよいのでしょうか? よろしくお願いします。 #include <iostream> #include <string> using namespace std; int main( ) { string str1="ABCDEF"; string str2="0123"; string str3; string q; do { (ウ) ; cout << str3 << endl; (エ) ; cout << str1 << endl; cout << "quit?"; cin >> q; } while ( (オ) ); cout << "終了" << endl; return 0; } <実行結果(出力結果)> ABCDEF0123 ABC123DEF quit?q ABC123DEF0123 ABC123123DEF quit?qu ABC123123DEF0123 ABC123123123DEF quit?quit 終了