C++ストリーム系の雑なメモ

文字列ストリームstrstreamは本当に文字配列をラップしただけであり、メモリ管理がクラスと使用者の間で行ったり来たりするので非推奨。
stringstreamを使うこと。

IO系インスタンスをbool型へ変換した場合、!fail()と同等。
fail()は(rdstate() & (ios::badbit | ios::failbit))の結果となり、つまりfailかbadどちらかのビットが立っていればtrue。

good()は何も異常がない(異常とはeof、fail、badのいずれか(又は複数)の状態)ことを表す。

以下に示すコードでは、getline関数の戻り値が入力されたストリームの参照であることを利用し、while (!ss.fail())と同等のことをしている。
!fail()ではeofのフラグが立っていたとしてもfalseを返さないため、このコードは無限ループをしてしまうように思える。
だが、そんなことはなくこのプログラムは文字を表示しきった後に止まることができる。
ストリーム系クラスは、入出力の前にsentryというオブジェクトを生成する。
このオブジェクトがコンストラクタでストリームのgood()を確認し、もしfalseならばfailビットを立ててくれるのである。
つまり、eof()がtrueの状態でさらに入出力を行うと、自動的にfailビットが立つ。
それと、getlineは改行文字を省いてくれる。

#include <iostream>
#include <sstream>
#include <string>
using namespace std;

#define LINE(text) #text "\n"

int main() {
    // 「Hello World!」と表示するC言語コードを持つ文字列ストリーム
    stringstream ss(
        LINE(#include <stdio.h>)
        LINE(int main() {)
        LINE(puts("Hello World!");)
        LINE(return 0;)
        LINE(})
    );

    string line;
    while (getline(ss, line)) {
        cout << line << endl;
    }
}

get()
getline()
raed()
readline()
これらのメソッドはどれも入力を読み取る機能を持つ。
get()、getline()はテキストデータを対象とした入力であり、入力末尾にヌル文字を付与する。
また、getline()は1行を読み取ることを前提としているため、1行すべて読み取れなかった場合にもsetstate(ios::failbit)が実行される。

read()はバイナリデータを対象とした入力であり、get()と違い入力末尾にヌル文字を付与しない。
また、read()は指定バイトサイズ入力を得られなかった場合にsetstate(ios::failed)を実行する。
readsome()は指定サイズバイトを得られない場合でも何もしない。