2.10 インデックス付け
インデックスは、通常コンパイラの <stddef.h> で定義された符号なしの整数である型 size_t を持ちます。size_t 型が符号なしであるため、16 ビットの DOS 環境ではインデックスの大きさは最大 64Kマイナス 1 になります。
無効なインデックスは、<rw/defs.h> で定義されている特殊な値 RW_NPOS として表わされます。
2.9 埋め込みヌル
Tools.h++ のクラスはすべて、RWCString および RWWString を含め、埋め込みヌルを持つ文字セットに対応しています。これにより、Tools.h++ のクラスはマルチバイトの文字セットと共に使用することができます。
2.8. 8 ビット対応
Tools.h++ のすべてのクラスは、8 ビット対応です。つまり、Tools.h++ のクラスはどれも ISO Latin-1 などの 8 ビットコードセットと共に使用できます。
2.7 マルチスレッド保証
コンパイラのリリースノートにしたがって適切なオプションでコンパイルする場合、Tools.h++ はマルチスレッドに対応します。つまり、Tools.h++ のすべての関数はマルチスレッド環境でも、シングルスレッド環境と同じように動作します。もちろんこれは、プログラムがスレッド間で個々のオブジェクトを共有しない、またはスレッド間で共有されているオブジェクトを操作中にロックすることを前提としています。Tools.h++ は、十分な内部ロックを行って独自の内部統合性を保持し、適切なマルチスレッド対応のシステム呼び出しを使用します。
2.5メモリの割り当てと解放
オブジェクトがヒープ領域に割り当てられている場合、それを削除するのは誰の役割でしょうか? 他社のライブラリでは、誰がオブジェクトを所有しているかが問題になる場合があります。
ほとんどの Rogue Wave のクラスでは、非常に簡単な対策をとっており、ユーザがヒープ領域から何かを割り当てた場合は、それを解放するのは、そのユーザの責任になります。Rogue Wave ライブラリがヒープ領域から何かを割り当てた場合は、ライブラリが責任を持って解放します。
オブジェクトの作成に関しては、例外が 2 つあります。最初の例外は、演算子によるものです。
RWFile& operator>>(RWFile& file, RWCollectable*&); Rwvistream& operator>>(RWvistream& vstream, RWCollectable*&);
これらの演算子は、それぞれ RWFile または RWvistream からの RWCollectable を継承しているオブジェクトを復元します。これらは、ヒープ領域から割り当てられたオブジェクトへのポインタを返します。これを解放するのは、ユーザの責任です。
2 番目の例外は、メンバ関数によるものです。
RWCollection* RWCollection::select(RWtestCollectable, void*)const;
この関数は、ある選択基準を満たすメンバとともに、ヒープ領域から割り当てられたコレクションへのポインタを返します。終了したら、このコレクションを削除するのもユーザの責任です。
また、オブジェクトの削除に関する例外もあります。多くのコレクションクラスでは、メソッド clearAndDestroy() を使うことができます。これは、コレクションからすべてのポインタを取り除き、それぞれ解放します。ただし、clearAndDestroy() を使用する場合は、そのコレクションのポインタすべてを削除しても問題が起きないかどうかを判断するのは、ユーザの責任となります。
これらのメソッドについて詳しくは、Tools.h++ Class Referenceを参照してください。
2.4 共通メンバ関数
クラスはすべて、その分類にはかかわらず、似たようなプログラミングインタフェースを持っています。この節では、その共通機能について説明します。
2.4.1永続性
Tools.h++ は、以下のメンバ関数を使ってClassName 型のオブジェクトを RWFile や Rogue Wave 仮想ストリームへ格納し、復元します。
RWFile& operator<<(RWFile& file, const ClassName&); RWFile& operator>>(RWFile& file, ClassName&); Rwvostream& operator<<(RWvostream& vstream,const ClassName&); Rwvistream& operator>>(RWvistream& vstream, ClassName&);
ANSI-C ファイル I/O をカプセル化するクラス RWFile は、オブジェクトをバイナリ形式で保存します。その結果、ファイルへの格納と取り出しが効率的に行われます。RWFile について詳しくは、Tools.h++ User’s Guideの第 7 章を参照してください。
クラス RWvistream と RWvostream は Rogue Wave 仮想ストリーム機能が使用する抽象基底クラスです。最終の出力形式は、特殊クラスによって決定されます。例えば、RWpistream と RWpostreamは、それぞれ RWvistream と RWvostream から派生した 2 つのクラスです。これらのクラスは、移植可能な ASCII 形式を使ってオブジェクトを格納または取り出します。結果は異なるオペレーティングシステム間で転送することができます。これらのクラスについて詳しくは、Tools.h++ User’s Guide の第 6 章を参照してください。
RWFile または Rogue Wave ストリームのどちらに格納するかの判断は、ユーザに任されています。RWFileへの格納は、速い代わりに、別のホストマシンやオペレーティングシステムに結果を移植するときに制限が生じます。Rogue Wave ストリームへの格納は、速度に欠ける代わりに、異なるマシン間で移植可能な形式や、分散型計算のためのXDRストリームによるカプセル化などの、便利な機能を持つ特殊クラスが使えます。
2.4.2 格納サイズ
次の共通メンバ関数は、RWFileが ClassName 型オブジェクトを格納するのに必要な、二次格納領域のバイト数を返します。
Rwspace ClassName::binaryStoreSize() const; Rwspace ClassName::recursiveStoreSize() const;
メンバ関数は、次の関数を使用します。
RWFile& operator<<(RWFile& file, const ClassName&);
上記のメンバ関数は、クラス RWFileManager および RWBTreeOnDisk
を使うオブジェクトを格納するときに便利です。RWCollectable から継承するオブジェクトの場合、2 番目のメンバ関数 recursiveStoreSize() は、再帰格納で使用されているバイト数を計算します。これは、次の関数を使用します。
RWFile& operator<<(RWFile& file, const RWCollectable&)
あらゆるストリームに対して、RWAuditStreamBuffer クラスを使ってバッファに渡されるバイト数を数えることができます。つまり、このクラスは、上記のメンバ関数 recursiveStoreSize() がファイルに対して与えるのと同じ機能を、ストリームに提供します。RWAuditStreamBuffer について詳しくは、Tools.h++ Class Reference を参照してください。
2.4.3 ストリーム I/O
多重定義された左シフト演算子 << は、最初の引数として ostream オブジェクトをとり、人間が読める形式でオブジェクトの内容を出力します。逆に、多重定義された右シフト演算子 >> は、最初の引数として istream オブジェクトをとり、人間が読める形式でストリームからオブジェクトを読み取り、分割します。
ostream& operator<<(ostream& ostr, const ClassName& x); istream& operator>>(istream& istr, const ClassName& x);
多重定義された左シフトおよび右シフト演算子は、永続性演算子と対照を成します。
Rwvostream& operator<<(RWvostream& vstream, const ClassName&); Rwvistream& operator>>(RWvistream& vstream, ClassName&);
永続性シフト演算子は、ストリームへ格納およびストリームから復元しますが、必ずしも「人間が読める」形式でそれを実行するとはかぎりません。
2.4.4 比較
ほとんどのクラスが比較と同等のメンバ関数を持ちます。
int compareTo(ClassName*) const; RWBoolean equalTo(ClassName*) const;
また、論理演算子の対を持ちます。
RWBoolean operator==(const ClassName&) const; RWBoolean operator!=(const ClassName&) const; RWBoolean operator<=(const ClassName&) const; RWBoolean operator>=(const ClassName&) const; RWBoolean operator<(const ClassName&) const; RWBoolean operator>(const ClassName&) const;
2.2 抽象基底クラス
Tools.h++ には、抽象基底クラスといろいろな機能のフレームワークを提供する特殊化クラスが含まれています。以下の表は、機能と抽象基底クラスの関係を示したものです。抽象基底クラスの場合は、Tools.h++ Class Referenceの各クラスごとの説明に明記されています。
表 1.抽象基底クラスと機能
- 機能
- クラス
- 参照箇所
- Locale
- RWLocale
- 16.4 節
- 時間帯
- RWZone
- 16.4 節
- 仮想ストリーム
- RWvistream RWvostream
- 第 6 章
- 多形永続性
- RWCollectable
- 第 14 章
- 仮想ページヒープ
- RWVirtualPageHeap
- 『Class Reference』
- モデルビューコントローラ抽象化
- RWModel RWModelClient
- 『Class Reference』
2.1 具体クラス
具体クラスは、以下のクラスから構成されています。:
- 第 3 章から第 5 章で説明されている、日付、時刻、文字列などを表わす単純クラス
- 第 11 章で説明されているテンプレートベースのコレクションクラス
- 第 12 章で説明されている、プリプロセッサ <generic.h> を使う汎用コレクションクラス
2.1.1 単純クラス
Tools.h++ には、軽量化された単純クラスが多く含まれています。軽量化されたクラスとは、時間のかからない初期設定子とコピーコンストラクタを持つクラスを意味します。単純クラスには、RWDate (日付)、 RWTime(時刻、各種の時間帯および地域に対応)、RWCString (シングルおよびマルチバイト文字列)、RWWString (ワイド文字)、および RWCRegexp または RWCRexpr (正規表現) などがあります。これらのクラスのほとんどは、4バイト以下で保持することができ、また非常に簡単なコピーコンストラクタ(通常1ビットコピー)を持ち、仮想関数は持っていません。Tools.h++ Class Referenceを参照してください。
2.1.2 テンプレートベースのコレクションクラス
テンプレートベースのコレクションクラス (略してテンプレート) には、速度と型保証という利点があります。しかし、コードサイズを減らすためには、あまり使わないようにしてください。テンプレートは多くの異なる型で使用できますが、各型がまったく新しいクラスを生成するために、コードサイズが大きくなる可能性があります。使用コンパイラで標準 C++ ライブラリが使える場合は、標準 C++ ライブラリをもとにしている Tools.h++ テンプレートベースコレクションを使用できます。使用コンパイラで標準 C++ ライブラリを使えない場合でも、11.3.1節および 11.10 節に説明されている、サブセットのテンプレートを使用できます。
2.1.3 汎用コレクションクラス
汎用コレクションクラスは、C++ コンパイラに付属しているプリプロセッサマクロ<generic.h> を使用するクラスです。このクラスは、テンプレートに対応していないコンパイラに対しては、型保証がされているために、テンプレートとほとんど同じように扱えます。このため、移植性が高いとも言えます。ただし、プリプロセッサにかなり依存しているため、この汎用コレクションクラスを含むコードで、デバッガを使用することが困難になる場合があります。さらに詳しくは、第 12 章を参照してください。
A.1 Tools.h++ コレクションクラスの選択
選択チャートには、コレクションに格納するデータについての質問が含まれています。選択チャートにざっと目を通すことにより、作成するプログラムとそのデータにどの Tools.h++ コレクションが最適であるかが分かります。
A.1.1 選択チャートの使い方
選択チャートを見やすくするために、各選択肢の質問は簡潔になっています。次に、選択肢の質問について解説します。
コレクション内のデータの順序には意味がありますか?
コレクションの中には、コレクション内のデータの位置を制御できるものがあります。例えば、配列やベクトル、およびリンクリストはデータを「順序付きで」提示します。特定の順序で、または数値インデックスに基づいてデータにアクセスする必要がある場合、順序には意味があります。
重複項目を許可しますか?
コレクションの中には、コレクション内にすでに存在している項目と等しい項目を挿入できないものがあります (通常、この種のコレクションはセットと呼ばれます)。別の種類のコレクションには、複数の同一項目を保持する様々な方法があり、重複項目の挿入を許可します。Tools.h++ コレクションには、重複を調べる機構と重複項目を保持する機構の両方が備えられています。
順序付けは本質的なものですか、それとも外部的なものですか?
コレクション内のデータがそれを挿入する方法によって制御される場合は、「順序が外部的に決定される」と言います。例えば、ベクトルやリンクリストは、外部的に順序付けられています。データがコレクションによって使用されるアルゴリズムによって決定された位置に格納される場合は、順序付けは「本質的」です。例えば、格納されたベクトルやバランスツリーは本質的な順序を持ちます。
外部キーによってデータにアクセスしますか?
値とは異なるキーを基準にして値にアクセスする場合、「外部キーによってデータにアクセスする」と言います。例えば、「電話番号リスト」は、電話番号というデータを、名前の形式をとったキーに関連付けます。逆に、「委員会メンバのリスト」は、名前の形をとったデータだけになります。情報を取得するためには、キーを必要としません。
数値インデックスでデータにアクセスしますか?
配列またはベクトルに格納されているオブジェクトには、数値インデックスでアクセスします。例えば、数値インデックス「12」を用いてオブジェクトを見つけ、12
という位置にあるオブジェクトにアクセスします。
自身との比較によってデータにアクセスしますか?
明示的なインデックスやキーのいずれとも一緒に格納されていないデータは、検索データとコレクション内のデータの一致を探すことによって見つけることができます。前述した委員会メンバのリストは、この種類のデータの例です。Set や Bag は自身との比較によってアクセスするコレクションの例です。
自身との比較によってデータにアクセスする場合は、どの種類の一致基準を使用するかを知る必要があります。一致には、あるオブジェクトを別のオブジェクトと直接比較する「等値性」を基準にすることも、オブジェクトのアドレスを比較し、オブジェクトが同一であるかどうかを調べる「アイデンティティ」を基準にすることもできます。
最適のアクセス方式は、リンクノードによるものですか?
リンクノードを利用するコレクションは、通常リストと呼ばれます。リストでは、コレクションの両端にあるデータに素早くアクセスでき、コレクションの真ん中にデータを効率よく挿入することができます。ただし、コレクションの真ん中にあるデータに頻繁にアクセスする必要がある場合、リストは他のコレクションに比べてそれほど効率的ではありません。
頻繁にアクセスするデータがコレクションの両端にありますか?
処理しなければならないデータの量が分からない場合は頻繁にありますが、処理するほとんどのデータは、コレクションの最も新しいデータか、最も古いデータです。最後に追加されたデータを処理するのに最も効率的なのは、「後入れ先出し」方式を持つコレクションです。後入れ先出し (LIFO) のコンテナは「スタック」です。先入れ先出し (FIFO) 方式でデータを処理するコレクションは、「待ち行列」と呼ばれます。最新データと最古データの両方に効率的にアクセスできるコレクションは、「両頭列」あるいは Deque (Double Ended Queue) と呼ばれます。
リンクリストの場合-データにリストの一方からだけ、または両方からアクセスする必要がありますか?
一重リンクリストはサイズが小さいのですが、リストの「正面」からだけアクセスできます。二重リンクリストは、より柔軟性のあるアクセス方式を持ちますが、格納されている各オブジェクトごとに追加のポインタを必要とします。
数値インデックスでアクセスするコレクションの場合-コレクションを自動的にサイズ変更する必要がありますか?
コレクションに格納する項目の最大数があらかじめ分かっている場合は、固定サイズのコレクションを選択する方がより効率的に挿入と削除を行うことができます。反対に、ほとんど無制限に拡張する必要がある場合は、現在格納しているデータ量に合わせて自動的にサイズを調整するコレクションを選択するべきです。
A.1.2 その他の選択基準
どのコレクションを選択するかは、これまでの経験や直観を含め、数多くの要素に依存します。選択チャートの質問の他に、どのコレクションを選択するかを決める上で次の質問も考慮してください。
複数コレクションで単一オブジェクトを保持する必要がありますか?
「はい」の場合は、ポインタベースのコレクションを使用します。
コピーするのに時間のかかるオブジェクトを収集しますか?
「はい」の場合は、ポインタベースのコレクションを使用します。
ポインタベースのコレクションを使用しなければならない理由がありますか?
「いいえ」の場合は、値ベースのコレクションを使用します。
コレクション内のオブジェクトの順序を外部的に制御しますか?
「はい」の場合は、ベクトルやリストなどのシーケンスコレクションを使用します。
挿入後、コレクション内の項目が変更可能である必要がありますか?
「はい」の場合は、シーケンスコレクションまたはマッピング (辞書) コレクションを使用します。マップと辞書は、不変のキーを持ちますが、値は変更可能です。
コレクションがオブジェクトの比較を基準に独自の順序を保持するようにしますか?
「はい」の場合は、セット、マップ、あるいはソート済みコレクションを使用します。
数値インデックスによってコレクション内のオブジェクトにアクセスしますか?
「はい」の場合は、シーケンスコレクションまたはソート済みコレクションを使用します。
非数値キーによって値を検索する必要がありますか?
「はい」の場合は、マップまたは辞書を使用します。
比較するオブジェクトを指定して、コレクション内のオブジェクトにアクセスしますか?
「はい」の場合は、セット、マップ、あるいはハッシュベースのコレクションを使用します。
意味のある順序付けをなしで済まし、その代わりメモリをキーによる定時間のルックアップに使いますか?
「はい」の場合は、ハッシュベースのコレクションを使用します。
必要に応じて拡張または縮小するコレクションで高速のルックアップと挿入が必要ですか?
「はい」の場合は、B-ツリー、あるいは新しい標準 C++ ライブラリを基にした連想コンテナを使用します。
メモリにデータすべてを読み込まずに、アクセスする必要がありますか?
RWBTreeOnDisk または RWTValVirtualArray を使用します。

