前節での注意とは別に、ストリームバッファをストリーム間で意図的に共有する場合があります。この節では、これらの点について検討します。
同じストリームに対して、書式設定と種類が異なる出力が必要な場合など、異なる出力間で、書式設定を切り替える代わりに、ストリームバッファを共有する 2 つの独立したストリームを用意することができます。ストリームは、異なる書式設定を持つことになりますが、出力は同じストリームバッファに書き込まれます。次にその例を示します。
ofstream file1("/tmp/x");
ostream file2(file1.rdbuf()); //1
file1.setf(ios_base::fixed, ios_base::floatfield); //2
file1.precision(5);
file2.setf(ios_base::scientific, ios_base::floatfield);
file2.precision(3);
file1 << setw(10) << 47.11 << '\n'; //3
file2 << setw(10) << 47.11 << '\n'; //4
| //1 | file2 のストリームバッファは、file1 のストリームバッファに置き換えられます。その後、両方のストリームでこのバッファを共有します。 |
| //2 | 両方のファイルに異なる書式設定を作成します。 |
| //3 | この出力は、47.11000 となります。 |
| //4 | この出力は、4.711e+01 となります。 |
上記の例で、file2 は、出力ファイルストリームではなく必ず出力ストリームとします。ファイルストリームからは、ファイルストリームバッファを切り替えることができないためです。
同様に、ストリームバッファを共有する別々のストリームを使用して、ロケール間の切り替えをなくすことも可能です。これは、多言語テキストを同じストリームに使用するときに有用です。次にその例を示します。
ostringstream file1;
ostream file2(file1.rdbuf());
file1.imbue(locale("De_DE"));
file2.imbue(locale("En_US"));
file1 << 47.11 << '\t';
file2 << 47.11 << '\n';
cout << file1.str() << endl; //1
| //1 | 出力は、47,11 47.11 になります。 |
図 32 では、ストリームバッファにはストリームのロケールオブジェクト以外に、専用のロケールオブジェクトがあるという問題があります。

6.4.4 節では、以上 2 つのロケールオブジェクトの役割を説明しました。すなわち、数値エンティティの処理は、ストリームから数値ファセットに委託されます。ストリームバッファでは、バッファの内容と外部デバイスから移送される文字間の文字変換に、そのロケールのコード変換ファセットを使用します。
一般に、ストリームのロケールとストリームバッファのロケールは同じものです。しかし、異なるロケールの 2 つのストリーム間でストリームバッファを共有する場合は、ストリームバッファで使用するロケールを指定する必要があります。20
ストリームバッファのロケールを設定するには、次のように pubimbue() 関数を呼び出します。
file1.imbue(locale("De_DE"));
file2.imbue(locale("En_US"));
file1.rdbuf()->pubimbue(locale("De_DE"));
共有ストリームバッファでも、ストリームに対する読み取りアクセスおよび書き込みアクセスを実行することができます。
filebuf fbuf; //1
fbuf.open("/tmp/inout",ios_base::in|ios_base::out); //2
istream in(&fbuf); //3
ostream out(&fbuf); //4
cout << in.rdbuf(); //5
out << "..." << '\n' ; //6
| //1 | ファイルバッファを作成します。 |
| //2 | そのバッファをファイルに接続します。ファイルの読み取りおよび書き込みが必要な場合、そのファイルは入出力モードで開く必要があります。 |
| //3 | ファイルバッファ fbuf に使用する入力ストリームを作成します。 |
| //4 | 同様にファイルバッファ fbuf を使用する出力ストリームを作成します。 |
| //5 | ファイルの内容をすべて読み取り、標準出力ストリームに挿入します。その後、ファイル位置はファイルの最後になります。 最も効率よくファイルの全内容を読み取るには、rdbuf() 関数を使用します。これは、基本ストリームバッファオブジェクトまでのポインタを返す関数です。ストリームバッファポインタを使用する挿入子も利用することができます。これは、バッファの内容を別のストリームに挿入するときに使用します。 |
| //6 | 出力をファイルに書き込みます。現在のファイル位置は、ファイルの最後なので、出力はすべてファイルの最後に挿入されます。 |
ファイルの読み書きには、双方向ストリームを使用するとより簡単で、エラー発生の可能性も少なくて済みます。上記の例を双方向ストリームを利用したコードに書き直すと、次のようになります。
fstream of("/tmp/inout");
cout << of.rdbuf();
of << "..." << '\n' ;
図 33 と 図 34 を比較すると、解法に違いがあることがわかります。図 33 に示すストリームバッファを共有する入出力ストリームでは、異なる書式設定、異なるロケール、異なる例外マスクなどを使用することができます。

しかし、図 34 に示す双方向ストリームでは、1 つの書式設定、ロケールしか使用できません。

双方向ストリームを使用するときに、入力演算と出力演算に異なる設定を使用できないのは明らかです。ファイルや文字列を読み書きするのであれば、ストリームバッファを共有する入力ストリームと出力ストリームを作成するよりは、双方向ファイルまたは双方向文字列ストリームを私用する方が便利です。双方向ストリームは宣言が簡単で、ストリームバッファオブジェクトの寿命に注意する必要がありません。
注: 2 つのストリームでストリームバッファを共有するよりも、双方向ファイルや双方向文字列ストリームの方が、ファイルや文字列に対する読み書きに適しています。
Copyright (c) 1998, Rogue Wave Software, Inc.
このマニュアルに関する誤りのご指摘やご質問は、電子メールにてお送りください。
OEM リリース, 1998 年 6 月