stringstreamは正確には何をしますか?


107

私は昨日からC ++を学ぼうとしていますが、このドキュメントを使用しています:http : //www.cplusplus.com/files/tutorial.pdf(32ページ)。ドキュメントにコードを見つけて実行しました。価格にRs 5.5、数量に整数を入力してみましたが、出力は0でした。5.5と6を入力してみましたが、出力は正しいものでした。

// stringstreams
#include <iostream> 
#include <string> 
#include <sstream> 

using namespace std; 

int main () 
{ 
  string mystr; 
  float price = 0; 
  int quantity = 0; 

  cout << "Enter price: "; 
  getline (cin,mystr); 
  stringstream(mystr) >> price; 
  cout << "Enter quantity: "; 
  getline (cin,mystr); 
  stringstream(mystr) >> quantity; 
  cout << "Total price: " << price*quantity << endl; 
  return 0; 
}

質問:mystringコマンドは正確には何をしますか?文書からの引用:

「この例では、標準入力から間接的に数値を取得します。標準入力から直接数値を抽出する代わりに、標準入力(cin)から文字列オブジェクト(mystr)にラインを取得し、整数を抽出しますこの文字列の値をint(量)型の変数に変換します。 "

私の印象では、関数は文字列の不可欠な部分を取り、それを入力として使用します。

(私はここで質問する方法を正確に知りません。私はプログラミングも初めてです)ありがとうございます。


18
この例はちょっと変です、私はstringstreamそのように使用されるのを見たことがありません。私は通常、ラインをロードし、それを変換しているのでしかし、これは明らかに、ここで少し利点があり、部品によって抽出cin された入力ストリームがすでに...だからがcin >> price >> quantity;はるかに簡単であることでしょう。それがcplusplus.comチュートリアルを使用しない正当な理由です。
Bartek Banachewicz 2013

6
そのチュートリアルがC ++への私の最初の暴露であったことはおかしい。振り返ってみると、それはかなり貧弱で不完全です。代わりに私は良い本を勧めます。
jrok

@BartekBanachewicz多分彼らはちょうどどのようにstringstream機能するかを示すために例を考え出す必要がありました。それはおそらく奇妙なものでもあります=)しかし、それはあなたが文字列をストリームとして扱うことができることを示しています。
luk32

より高度な使用法の紹介ではない場合、それstringstreamは明らかに間違った例です。そして、それがそうであったとしても、それは別様に書かれるべきです。
j_kubik 2013

1
@trojansdestroy文字列の基礎となるすべてのプリミティブを理解せずに文字列ストリームを理解することはできないため、チュートリアルを読むことがその点でどのように役立つかはわかりません。
Bartek Banachewicz 2013

回答:


163

stringstreamを使用して、文字列と他の数値型の間で変換するのが非常に便利な場合があります。の使用方法はの使用方法stringstreamと似ているiostreamため、覚えるのに負担はありません。

文字列ストリームは、文字列の読み取りと文字列へのデータの書き込みの両方に使用できます。主に文字列バッファで機能しますが、実際のI / Oチャネルはありません。

stringstreamクラスの基本的なメンバー関数は次のとおりです。

  • str()、そのバッファの内容を文字列型で返します。

  • str(string)バッファの内容を文字列引数に設定します。

文字列ストリームの使用例を以下に示します。

ostringstream os;
os << "dec: " << 15 << " hex: " << std::hex << 15 << endl;
cout << os.str() << endl;

結果はdec: 15 hex: fです。

istringstream ほぼ同じ使用法です。

要約すると、stringstreamは、独立したI / Oデバイスのように文字列操作する便利な方法です。

ちなみに、クラス間の継承関係は次のとおりです。

文字列ストリームクラス


19

質問に答える。stringstream基本的に、stringオブジェクトをのように扱い、その上でstreamすべてのstream関数と演算子を使用できます。

主にフォーマットされた出力/入力の良さのために使用されるのを見ました。

1つの良い例はc++、数値をストリームオブジェクトに変換する実装です。

可能な例:

template <class T>
string num2str(const T& num, unsigned int prec = 12) {
    string ret;
    stringstream ss;
    ios_base::fmtflags ff = ss.flags();
    ff |= ios_base::floatfield;
    ff |= ios_base::fixed;
    ss.flags(ff);
    ss.precision(prec);
    ss << num;
    ret = ss.str();
    return ret;
};

少し複雑かもしれませんが、かなり複雑です。stringstreamオブジェクトを作成しss、そのフラグを変更し、を使用してオブジェクトに数値を入力しoperator<<、を介して抽出しstr()ます。operator>>使用できると思います。

また、この例では、stringバッファーは非表示になっており、明示的に使用されていません。しかし、考えられるあらゆる側面とユースケースについて書くには長すぎる投稿です。

注:おそらく、SOの誰かからそれを盗んで洗練されたものですが、元の著者には言及していません。


3
注:の使用retは不要return ss.str();です。
Matthieu M.

@MatthieuM。RVOがそのように記述されている場合にキックインするのか、またはss.str()によって返されたオブジェクトが出口点を通過しても存続するのかはわかりませんでした。このようにして、私がコピーを作成していることがわかり、RVOが機能します。しかし、あなたはおそらく正しいです。
luk32

実際、RVOには2つの形式があります。URVO(名前なし、つまり一時的なもの)とNRVO(名前付き)です。ほとんどのコンパイラはRVOを実装していますが、一部のコンパイラはRVOのみに制限しています(ビルドオプションによって異なります)。。一般的に、しかし、他の要因の多くは、あなただけの可能なクリーンなコードを書く必要がありますので、考慮に入れないRVOがでキックするかどうかについてはあまり心配するがある
マシューM.を

NRVOは一般的ですが(URVOと同様)、ムーブコンストラクターのため、問題にはなりません。
Rapptz 2013

18

C ++ Primerから:

istringstreamのタイプは読み込み、文字列をostringstreamは書き込みの文字列を、とにstringstreamは、読み取りおよび書き込みの文字列を

stringstreamを使用すると便利で簡潔な場合があります。

ケース1

それからある解決策の一つのために、このleetcode問題stringstreamの使用が効率的かつ簡潔である非常に適切なケースを示しています。

仮定aしてb、文字列形式で表現複素数である、我々はの乗算の結果を取得したいab文字列の形式でも。コードは次のとおりです。

string a = "1+2i", b = "1+3i";
istringstream sa(a), sb(b);
ostringstream out;

int ra, ia, rb, ib;
char buff;
// only read integer values to get the real and imaginary part of 
// of the original complex number
sa >> ra >> buff >> ia >> buff;
sb >> rb >> buff >> ib >> buff;

out << ra*rb-ia*ib << '+' << ra*ib+ia*rb << 'i';

// final result in string format
string result = out.str() 

ケース2

これは、指定されたパス文字列を簡略化する必要があるリートコードの問題からも発生します。stringstream を使用するソリューションの1つは、私が見た中で最もエレガントです。

string simplifyPath(string path) {
    string res, tmp;
    vector<string> stk;
    stringstream ss(path);
    while(getline(ss,tmp,'/')) {
        if (tmp == "" or tmp == ".") continue;
        if (tmp == ".." and !stk.empty()) stk.pop_back();
        else if (tmp != "..") stk.push_back(tmp);
    }
    for(auto str : stk) res += "/"+str;
    return res.empty() ? "/" : res; 
 }

stringstreamを使用しないと、そのような簡潔なコードを作成することは困難です。


2

で空白と空白で区切られた英数字と整数を入力しましたmystr

次に、最初のトークン(空白区切り)をに変換しようとしましたint

最初のトークンはRSで、これはに変換できずint、mypriceにゼロが残っていました。

2回目にint値のみを入力した場合、すべてが期待どおりに機能しました。

コードが失敗する原因となったのは偽のRSでした。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.