Rogue Wave バナー
前へマニュアルの先頭へ目次次へ

18.2 新しいストリームバッファクラスの派生

一般には、新しい streambuf クラスの派生は使用しませんが、特別な動作が必要な場合には非常に有用な機能です。たとえば、ログファイルが無限に増殖するのを防ぐために、一定のサイズになると先頭から書き込みを行うログブックストリームを例に挙げます。この新しいクラスを実装するには、まず、新しいストリームバッファ型を派生させる必要があります。一番簡単な方法は、filebuf から派生させ、限定公開の仮想関数のいずれかを実装する方法です。

template <class charT, class traits>
class logbuffer : public std::basic_filebuf<charT,traits>
{
  
  std::streamsize max_size;
  
public:
  typedef charT            char_type;            // 1
  typedef traits::int_type int_type;
  typedef traits::off_type off_type;
  typedef traits::pos_type pos_type;
  typedef traits           traits_type;
  
  logbuffer(std::streamsize sz) : max_size(sz)   // 2
  { ; }
  
protected:
  int_type overflow(int_type c = traits::eof()); // 3

};
//1 すべてのストリームに 3 種類の型を定義します。
//2 このコンストラクタには、ログファイルのサイズを限定するためのサイズパラメータが必要です。
//3 put 領域が一杯になって、ストリームでストリームバッファに対する書き込みを行うたびに、限定公開の仮想関数 overflow(char_type) が呼び出されます。ファイルが大きくなりすぎた場合は、この関数を再実装してファイルポインタを先頭にリセットします。

overflow 関数は、次のように実装します。

template <class charT, class traits>
logbuffer<charT,traits>::int_type
logbuffer<charT,traits>::overflow(logbuffer<charT,traits>::int_type c)
{
  using std::ios_base;
  using std::basic_filebuf;
  std::streamsize len = epptr() - pbase();                  // 1
  int_type ret = basic_filebuf<charT,traits>::overflow(c);  // 2
  
  if (seekoff(0,ios_base::cur) > max_size - len)            // 3
    seekoff(0,ios_base::beg);                               // 4
  return ret;                                               // 5
}
//1 まず、バッファの put 領域のサイズを局所変数に保存します。epptr()pbase() は、basic_streambuf の限定公開の関数であり、それぞれ put 領域の先頭と末尾を返します。他の限定公開の関数は、 get 領域の先頭と末尾を返し、さらに現在の getput の位置を返します。これらの関数の詳細については、『標準 C++ クラスライブラリ・リファレンス』を参照してください。
//2 次に、filebuf' の ovrflow を呼び出してバッファの put 領域をファイルに書き込みます。
//3 seekoff で現在のストリーム位置を確認し、その位置と最大ファイルサイズが put バッファよりも小さいかどうかを調べます。真の場合は、put 領域の次のフラッシュが、このファイルに設定した最大サイズを超えることになります。
//4 ログが大きくなりすぎた場合は、stream(file) の先頭にシークで戻ります。ストリームに対する今後の書き込みは、ログファイルの先頭から上書きされます。
//5 最後は、filebuf'の overflow 関数から取り出した値を返します。

新しい logbuf クラスを使用するには、新しい logstream クラスも必要です。

template <class charT, class traits>
class logstream : public std::basic_iostream<charT,traits>
{
  logbuffer<charT,traits> buf;               // 1
public:
  typedef charT            char_type;        // 2
  typedef traits::int_type int_type;
  typedef traits::off_type off_type;
  typedef traits::pos_type pos_type;
  typedef traits           traits_type;
  
  logstream(std::streamsize sz, char* file); // 3
  logbuffer<charT,traits> *rdbuf() const     // 4
  {
    return (logbuffer<charT,traits>*)&buf;
  }
};
//1 この非公開メンバーでは、logbuffer オブジェクトが得られます。
//2 再び、標準の型セットを定義します。
//3 このコンストラクタでは、指定した最大サイズとファイル名のストリームが作成されます。
//4 rdbuflogbuffer までのポインタを返します。

最後は、次のように新しいログストリームクラスを実装します。

template <class charT, class traits>
logstream<charT,traits>::logstream(std::streamsize sz, char* file)
    : buf(sz)
{
  using std::ios_base;
  
  init(&buf);                                          // 1
  if ( !buf.open(file, ios_base::out) )                // 2
    setstate(ios_base::failbit);
  buf.pubseekoff(0,ios_base::beg);                     // 3
}
//1 ios_base::init() 関数は規定クラスを初期化します。初期化では一部、ios_baselogbuffer までのポインタのインストールが行われるので、基底クラスはこのバッファにアクセスします。
//2 ファイルを開いて書き込みます。
//3 書き込みは、常に先頭から開始します。

この新しいログバッファの使用方法を次に示します。

int main ()
{
  using std::char_traits;
  using std::endl;
  
  logstream<char,char_traits<char> > log(4000,"test.log"); // 1
  for (int i = 0; i < 1000; i++)                           // 2
    log << i << ' ';                         
  log.rdbuf()->pubseekoff(0,std::ios_base::beg);           // 3
  int in = 0;
  log >> in;                                               // 4
  return 0;
}
//1 最大サイズが 4000 文字の logstream オブジェクトを作成し、ファイル test.log に接続します。
//2 0 から 999 までの整数をログファイルに書き出します。この数値の表示に必要な合計文字数とその間のスペースが、設定した最大サイズよりも大きくなります。
//3 ファイルの先頭までシークを行います。
//4 ファイルの最初の値を調べます。通常の fstream を使用した場合は、この値は 0 になります。これは最初に書き出される値です。しかし、logstream を使用してログの容量以上に書き出す設定になっているため、ログは先頭を一巡しており、得られる値は別の値になるはずです。

前へマニュアルの先頭へ目次次へ

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


OEM リリース, 1998 年 6 月