株式会社エス・スリー・フォー

[Tools.h++]10.1 コレクションクラスの格納方法

コレクションクラス (略してコレクションとも言う) の一般的な目的は、オブジェクトの格納と取り出しです。どのようにオブジェクトを格納するかをもとにして、コレクションクラスを分類することができます。値ベースのコレクションはオブジェクト自体を格納するのに対し、参照ベースのコレクションはオブジェクトへのポインタまたは参照を格納します。この違いにより、Tools.h++ のコレクションクラスの機能の使い方が変わります。

値ベースのコレクションクラスは、より簡単に理解し操作することができます。例えば、整数や倍精度のリンクリスト、あるいは short のハッシュ表を作成するときに使うコレクションクラスです。格納する型は、RWCStringのようにより複雑にすることができます。ここで重要な点は、これらは他のオブジェクトへのポインタを含んでいても、単に値のように動作するということです。オブジェクトを値ベースのコレクションクラスに挿入すると、コピーが作成されます。プロシージャは、関数呼び出しにおける C の値渡しの意味論に似ています。

参照ベースのコレクションクラスでは、他のオブジェクトへのポインタを格納し取り出します。例えば、整数や倍精度へのポインタのリンクリスト、あるいは RWCStringへのポインタのハッシュ表を作成することができます。

値ベースと参照ベースのプロシージャにおける違いを示す、2 つのコードをみてみましょう。

値ベースの例 参照ベースの例
/* RWCStringsのベクトル */
RWTValOrderedVector<RWCString> v;
RWCString s("A string");
v.insert(s);
/* RWCStringsへのポインタのベクトル */
RWTPtrOrderedVector<RWCString> v;
RWCString* p = new RWCString("A string");
v.insert(p);

どちらのコードも、ベクトル v に RWCString を挿入します。最初の例では、s が「A string」最初の例では、s が「A string」を含む RWCString オブジェクトです。v.insert(s) の行では、ベクトルに s の値をコピーします。ベクトル内にあるオブジェクトはオリジナルのオブジェクト s とは異なる別個のものです。2 番目の例では、p が RWCString オブジェクトへのポインタです。プロシージャ v.insert(p) が完了すると、v にある新しい項目が p と同じ RWCString オブジェクトを参照します。

10.1.1 メモリ管理について

ポインタは、占めるメモリ容量が小さく、操作時に計算量をあまり必要としないので、ポインタ操作を行う参照ベースコレクションは非常に効率的です。ただし、参照ベースコレクションでは、メモリ管理 (実際のオブジェクトの作成、管理、および破壊) はユーザの責任において行わなければなりません。同一オブジェクトへのポインタを 2 個作成し、1番目のポインタを使ってオブジェクトを削除すると、2 番目のポインタが意味のないものを指してしまうことになります。同様に、コレクションには格納されている値を間接参照しなければならないメソッドがあるので、決して nil ポインタを参照ベースのコレクションに挿入してはいけません。

ユーザ自身でメモリ管理を行う必要はありますが、参照ベースコレクションが必要なときには使うようにしてください。Tools.h++ クラスは便利なメンバ関数を持っており、多くの場合、格納されているオブジェクトの所有権がはっきりしています。速度とサイズにおける利点 (すべてのポインタのサイズが同じで、コードを大幅に再利用できる) を必要とする場合は、参照ベースコレクションを使ってください。(すべてのポインタのサイズが同じで、コードを大幅に再利用できる) を必要とする場合は、参照ベースコレクションを使ってください。オブジェクトを格納するのではなく単に指したい場合 (例えば、ダイアログリストで選択されているオブジェクト) も、参照ベースコレクションを使います。また、異種のオブジェクトから成るコレクションの場合、参照ベースによる手段しか使えない場合もあります。