ここでは、挿入子関数の改善方法について検討します。巨大な国別コードテーブルがあって、国別コードへのアクセスに時間がかかる状況を想定します。挿入子関数のパフォーマンスは、国別コードテーブルをキャッシュして直接アクセスするようにし、パフォーマンスのオーバーヘッドをなくすことで最適化することができます。
次のコードでは、基本キャッシュを行います。ストリームのロケールオブジェクトから電話ファセットオブジェクトを取り出し、国別コードテーブルを静的変数にコピーします。
ostream& operator<<(ostream& os, const phoneNo& pn) { locale loc = os.getloc(); const phone_put& ppFacet = use_facet<phone_put> (loc); // 基本キャッシュ static prefixMap_t codes = *(ppFacet.country_codes()); // キャッシュコードを使用した高度な出力 ... return (os); }
ストリームに組み込まれたロケールオブジェクトは変更されましたが、キャッシュされた静的国別コードテーブルが変更されなかった状況を想定してみます。キャッシュがデータで一杯になると、ストリームのロケールオブジェクトを変更しても、この挿入子関数のキャッシュは変更されません。これは望ましいことではありません。必要な対策は、新しいロケールオブジェクトが組み込まれるたびに何らかの通知を行って、キャッシュを更新することです。
以下の例では、コールバック関数で通知を行います。コールバック関数の登録は入出力ストリームで行います。クラス ios_base で次のように宣言します。
enum event { erase_event, imbue_event, copyfmt_event }; //1 typedef void (*event_callback) (event, ios_base&, int index); void register_callback (event_callback fn, int index); //2
//1 | 登録したコールバック関数は、次の 3 つのイベントに呼び出されます。
|
//2 | register_callback()
関数では、コールバック関数と、ストリームの
parray までのインデックスを登録します。imbue()、copyfmt()、
~ios_base() に対する呼び出しの間に、関数 fn
は引数インデックスとともに呼び出されます。イベントが発生すると、登録された関数は、登録時とは逆の順序で呼び出されます。
parray は、基底クラス ios_base の静的配列です。この配列までのインデックスを使用するには、xalloc() を使用します。また配列にアクセスするには pword(index) か iword(index) を使用します。図 16 にその方法を示します。 図 16 -- 静的配列 parray
|
キャッシュを更新するコールバック関数をインストールするには、parray までのインデックスを検索してキャッシュを作成し、そのコールバック関数をコンストラクタに登録するクラスを実装します。以下のコードに、その方法を示します。
class registerCallback_t { public: registerCallback_t(ostream& os ,ios_base::event_callback fct ,prefixMap_t* codes) { int index = os.xalloc(); //1 os.pword(index) = codes; //2 os.register_callback(fct,index); //3 } };
//1 | 配列までのインデックスを、xalloc() で検索します。 |
//2 | コードテーブルまでのポインタを pword() で配列に格納します。 |
//3 | コールバック関数とインデックスを登録します。 |
parray までのインデックスを使用して、実際のコールバック関数が後でキャッシュにアクセスします。
この段階では、ストリームのロケールを変更するたびにキャッシュを更新するコールバック関数がまだ必要です。以下のコードは、そのようなコールバック関数を示したものです。
void cacheCountryCodes(ios_base::event event ,ios_base& str,int cache) { if (event == ios_base::imbue_event) //1 { locale loc = str.getloc(); const phone_put<char>& ppFacet = use_facet<phone_put<char> > (loc); //2 *((phone_put::prefixMap_t*) str.pword(cache)) = *(ppFacet.country_codes()); //3 } }
//1 | イベントが、組み込んだロケールの変更であるかどうかを調べます。 |
//2 | ストリームのロケールから電話番号ファセットを検索します。 |
//3 | キャッシュに国別コードテーブルを保存します。キャッシュは、ストリームの parray でアクセスすることができます。 |
挿入子に関して、改善すべきところはすべて改善してきました。必要に応じてキャッシュを更新するコールバック関数が挿入子によって登録されます。登録は、クラス registerCallback_t の静的変数の宣言によって 1 回だけ行われます。
ostream& operator<<(ostream& os, const phoneNo& pn) { static phone_put::prefixMap_t codes = *(use_facet<phone_put>(os.getloc()).country_codes()); //1 static registerCallback_t cache(os,cacheCountryCodes,&codes);//2 // some sophisticated output using the cached codes ... }
//1 | 現在の国別コードテーブルがキャッシュされます。 |
//2 | コールバック関数 cacheCountryCodes が登録されます。 |
Copyright (c) 1998, Rogue Wave Software, Inc.
このマニュアルに関する誤りのご指摘やご質問は、電子メールにてお送りください。
OEM リリース, 1998 年 6 月