7

私は自分の ostream を作成することと、それに加えて、ostream のバッファーを処理するための streambuf について調査を行ってきました。私は実際にほとんどの作業を行っています。ストリームに (<<) を挿入して、問題なく文字列を取得できます。仮想関数 xsputn を実装することでこれを行います。ただし、ストリームに文字列の代わりに float または int を入力 (<<) すると、xsputn が呼び出されることはありません。

コードを確認したところ、ストリームが do_put を呼び出し、次に f_put を呼び出していることがわかりました。これは、最終的に一度に 1 文字ずつ float をバッファーに入れようとします。バッファーをスペースなしで残して、float と int のデータを取得すると、仮想関数の実装である overflow(int c) を呼び出すことができます。

ここに問題があります。フロートがいつバッファーに入れられたかを知る必要があります。別の言い方をすれば、ストリーミングされる特定の値に対してオーバーフローが呼び出されるのがこれが最後になるのはいつかを知る必要があります。したがって、それをバッファにコピーしてから、バッファがいっぱいになるのを待って関数を呼び出すことができます。

出力をキャッシュしてから、入力値ごとに一度に送信する必要があるという点で、ostream設計を悪用していることは確かです(<<)。

とにかく明確にするために、私が撮影しているものを別の方法で言い直します. 私が間違った方法で進んでいる可能性が非常に高いです。

継承された ostream と streambuf を使用して、それに値を入力し、型変換を処理できるようにしたいです。次に、その情報を別のオブジェクトに渡し、streambuf にハンドルを渡します (為に?)。そのオブジェクトには高価な i/o があるため、一度に 1 文字ずつデータを送信したくありません。

これが不明な場合は、事前に申し訳ありません。そして、お時間をいただきありがとうございます。

4

1 に答える 1

17

おおよそ正しいように聞こえますが、何をしているのかはあまり明確ではありません。念のため:ostreamを作成してインストールするための便利なコンストラクタstreambuf、デストラクタ、およびrdbuf適切なタイプのバッファを処理するための の実装を提供するだけです。xsputnそれが正しいと仮定すると、 yourでの定義streambufは純粋に最適化です。定義しなければならない重要な機能はoverflow. の最も単純な実装overflowは、単一の文字を取り、それをシンクに出力します。それを超えるものはすべて最適化です。たとえば、を使用してバッファを設定できsetpます。これを行うoverflowと、バッファがいっぱいになったとき、またはフラッシュが要求されたときにのみ呼び出されます。この場合、バッファも出力する必要があります (使用pbaseしてpptrアドレスを取得します)。(streambuf基本クラスはポインタを初期化して長さ 0 のバッファを作成するためoverflow、すべての文字に対して呼び出されます。) (非常に) 特定のケースでオーバーライドしたいその他の関数:

imbue: 何らかの理由でロケールが必要な場合。(現在の文字エンコーディングはロケールの一部であることに注意してください。)

setbuf: クライアント コードでバッファを指定できるようにします。(私見、通常はわざわざする価値はありませんが、特別な要件がある場合があります。)

seekoff: シークのサポート。私はこれを自分streambufの s で使用したことがないので、標準で読み取れる以上の情報を提供することはできません。

sync: フラッシュ時に呼び出され、バッファ内のすべての文字をシンクに出力する必要があります。呼び出しを行わないsetp(つまりバッファーがない) 場合は、常に同期しているため、操作を行わない可能性があります。 overflowまたはuflowこれを呼び出すか、両方で別の関数を呼び出すことができます。( と の唯一の違いはsyncuflowuflowバッファがある場合にのみ呼び出され、バッファが空の場合は呼び出されないことです。 syncは、クライアント コードがストリームをフラッシュした場合に呼び出されます。)

独自のストリームを作成するときは、パフォーマンスが別の方法で指示しない限り、シンプルに保ち、オーバーライドのみを行いますoverflow。パフォーマンスがバッファを決定する場合、通常、バッファをフラッシュするコードを別の関数に配置し、次の行に沿ってwrite(address, length) 実装overflowします。sync

int MyStreambuf::overflow( int ch )
{
    if ( pbase() == NULL ) {
        // save one char for next overflow:
        setp( buffer, buffer + bufferSize - 1 );
        if ( ch != EOF ) {
            ch = sputc( ch );
        } else {
            ch = 0;
        }
    } else {
        char* end = pptr();
        if ( ch != EOF ) {
            *end ++ = ch;
        }
        if ( write( pbase(), end - pbase() ) == failed ) {
            ch = EOF;
        } else if ( ch == EOF ) {
            ch = 0;
        }
        setp( buffer, buffer + bufferSize - 1 );
    }
    return ch;
}

int sync()
{
    return (pptr() == pbase()
            || write( pbase(), pptr() - pbase() ) != failed)
        ? 0
        : -1;
}

通常、私は気にしませんxsputnが、クライアント コードが多くの長い文字列を出力している場合は、役に立つ可能性があります。このような何かがうまくいくはずです:

streamsize xsputn(char const* p, streamsize n)
{
    streamsize results = 0;
    if ( pptr() == pbase()
            || write( pbase(), pptr() - pbase() ) != failed ) {
        if ( write(p, n) != failed ) {
            results = n;
        }
    }
    setp( buffer, buffer + bufferSize - 1 );
    return results;
}
于 2011-04-13T09:24:43.243 に答える