## 18.1 ストリームバッファクラス: シーケンスの抽象化

ストリームバッファには、標準 C++ ライブラリの入出力ストリームの移動と文字コード変換機能があります。また、ストリーム自体が表す書式設定層のソースとシンクのいずれか、または両方のはたらきがあります。バッファはファイルに文字を送信したり、文字列、メモリー配列、その他の宛先に文字を保存します。反対に、文字列、メモリー配列、ファイルから文字を受け取ることもあります。ストリームバッファは、必ずしも入力と出力の両方を処理するとは限らず、読み取りや書き込みの演算のいずれかを専門で行うこともあります。また、何らかの適切な方法でデータの変更や操作をする場合もあります。このことについては、新しいストリームバッファクラスの派生について説明している18.2 節で触れます。

### 18.1.1 ストリームバッファ層

ストリームと比較するとはるかに単純ですが、ストリームの場合と同様に、ストリームバッファもクラス階層で構成されています。確認のために、図 26 で説明したクラス階層を、次の図 37 で再度示します。

#### 図 37 -- ストリームバッファのクラス階層

クラス basic_streambuf では、理論上は無制限な機能を持つ、1 次元文字配列の基本的な抽象化を受け持ちます。他のストリームバッファは、すべてこのクラスから派生します。クラス basic_streambuf では、ストリームとストリームバッファ間の基本インタフェースも定義します。このインタフェースの実装のほとんどは、限定公開の仮想関数のセットに委託されており、実際に行うべき操作を派生クラスで処理することができます。basic_streambuf にあるこれらの関数には、すべてデフォルトの動作が設定されていますが、basic_streambuf オブジェクト自体には公開コンストラクタがないため、移送層では何も機能しません。ただし、basic_streambuf クラスには、具体的なストリームバッファを派生させるという役割があります。

クラス階層に示すように、入出力ストリーム機能では、3 つの派生ストリームバッファを定義します。この 3 つのバッファは、ファイル、文字列、メモリー内の文字配列に対する入出力を個別に処理します。

- クラス basic_filebuf には、ストリームとファイルのインタフェースをとるための移送層があります。
- クラス basic_stringbuf には、メモリー内の文字列と直接対話するための移送層があります。
- クラス strstreambuf では、文字配列に対する読み書きを行います。

以上 3 つの派生ストリームバッファでは、それぞれのタスクに応じた動作を実装し、streambuf インタフェースを拡張してソースや宛先の特定の要求に対応しています。たとえば、basic_filebuf には `open` 関数と `close` 関数があり、基本ファイルでそれぞれの演算を行い、basic_stringbuf には `str()` 関数があり、基本文字列のコピーを返します。

ストリームバッファはメモリー内で文字配列を実装し、ストリームを通じて受け渡しているデータの部分 (現在バッファにある部分) を表します。バッファでは、`put` 領域と `get` 領域を管理します。前者はストリームに書き込まれるまでバッファにある文字を保存します。後者は読み取り用の文字を保存します。どちらも、ストリームの種類 (読み取りか書き込みか) やストリームの状態 (たとえば、ファイルの末尾) によって空になります。

`put` 領域が一杯になると、その中の文字は限定公開の仮想関数 `overflow()` で書き出されます。`get` 領域が空になると、限定公開の仮想関数 `underflow()` で新しい文字セットが読み取られます。こうして、文字の実際の読み書きは、必要に応じて派生クラスに委託されます。たとえば、文字をファイルに書き込むオーバーフローの機能は filebuf に実装されており、オーバーフローが呼び出されるたびに、stringbuf は単純に文字を文字列にコピーします。

シーク処理と同期操作の処理方法は同じです。 同期操作では、ストリームバッファの状態と基本ソースとシンクの状態を同期させます。

### 18.1.2 ストリームバッファインタフェース

クラス basic_streambuf は、読み取り、書き込み、シーク、照会、地域対応化用の公開インタフェースを定義します。特定の動作を派生クラスで実装するため、このインタフェースを定義する公開関数のほとんどは、実際には限定公開の仮想関数に機能を委託しています。これらの関数の詳細については、『標準 C++ クラスライブラリ・リファレンス』を参照してください。以下の節では、公開インタフェースと、関数による仮想関数への委託について説明します。

読み取りの場合:

`in_avail()` は、現在バッファにあって読み取ることができる文字の数を返します。または、バッファが空の場合は、配下ソースから取り込むことのできる文字の数の推定値を返します。
デフォルトのストリーム `cin` のように推定値が得られない場合は、`-1` が返ります。

`snextc()` は、バッファ内の現在の位置を 1 文字分前進させ、現在示している文字を返します。ファイルの末尾に達すると、`ios_base::eof` を返します。

`sbumpc()` は、バッファ内で現在示している文字を返し、現在の位置を 1 つだけ増分します。

`sgetc` は、現在の位置の文字を返します。この関数では現在の位置は変更されません。

`sgetn(char_type* s, streamsize n)` は、`s` で示された文字配列に`n` 文字までの文字をバッファからコピーします。この関数は限定公開の仮想関数 `xsgetn()` に委託します。

最後の 4 つの関数を実行しても現在バッファで文字が得られない場合は、いずれも限定公開の仮想関数 `underflow` で新しい文字をフェッチします。

`sungetc` と `dsputbackc(char_type)` は、可能であれば、どちらも現在のポインタを 1 ステップ戻します。たとえば、`stdin` に接続されたバッファの先頭にあって戻ることができない場合は、どちらの関数でも、限定公開の仮想関数 `pbackfail()` の呼び出し結果が返ります。バッファ内の前の文字が関数の引数と一致しない場合は、関数 `sputback` も `pbackfail()` を返します。

書き込みの場合:

`sputc(char_type c)` は、文字 `c` を現在の位置のバッファにコピーし、位置を増分します。`write` 領域が一杯の場合は、限定公開の仮想関数 `overflow(c)` が呼び出されます。

`sputn(const char_type* s, streamsize n)` は、限定公開の仮想関数 `xsputn` に機能を委託します。その結果、最高で `n` 文字が `s` からバッファの `put` 領域までコピーされ、書き込み位置がその分増分されます。

位置決めの場合:

`pubseekoff` と `pubseekpos` は、それぞれの仮想関数 `seekoff` と `seekpos` に機能を委託します。これらの関数の動作は、派生ストリームバッファと必要なコードの種類の規約によって大きく異なります。`filebuf` に関するこれらの機能については、9.5 節のファイルの位置決めを参照してください。

ロケールの場合:

`pubimbue(const locale&)` と `getloc()` では、ストリームバッファの文字コード変換特性を設定し、取り出します。`pubimbue` は実際には限定公開の仮想関数 `imbue` に機能を委託します。`pubimbue` は、ストリームバッファの前回のロケールを返します。これは `pubimbue` に対する呼び出しの前に `getloc` で返される同じロケールです。

最後は、streambuf が内部文字バッファを設定する関数と、バッファと基本ソースやシンクを同期する関数を提供します。関数 `pubsetbuf(char_type*,streamsize)` は、機能を限定公開の仮想関数 `setbuf` に委託し、`pubsync` は機能を限定公開の仮想関数 `sync` に委託します。

18.2 節は、既存のストリームバッファクラスの 1 つから派生させて、新しい種類のストリームバッファを作成する方法を示したものです。streambuf で宣言した限定公開の仮想関数の 1 つを再実装して、filebuf の動作を変更しています。

Copyright (c) 1998, Rogue Wave Software, Inc.
このマニュアルに関する誤りのご指摘やご質問は、電子メールにてお送りください。

OEM リリース, 1998 年 6 月