超スマート・ポインタの C++ 版です。 基本的にはこちらも循環参照解決可能なスマート・ポインタです。 C 言語版では手動で操作していた参照カウントを 自動で操作するようになった点が便利だと思います。 対応環境は ansi C++ strict+pthread です。 ライセンスは LGPL ではなく MIT LICENSE です。 (download)
なぜ MIT LICENSE にしたかも書いておきます。 本体 (kgc.tar.gz) は改変部分を公開して欲しいので LGPL にしました。 初めは C++ ラッパ部分も LGPL にしようと思っていましたが 10 行を越える大きさの LGPL の template を利用すると 利用者側のソフトウェアまで LGPL に感染する可能性があるようなのです。 LGPL の該当箇所は
When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.)
「『ライブラリ』を利用する著作物」が、『ライブラリ』の一部であるヘッダファイルから採られたコード等を利用する場合、ソースコードはそうではなくても、その著作物をオブジェクトコードにしたものは『ライブラリ』の派生物になる可能性がある。これが真であるかは、その著作物が『ライブラリ』抜きでもリンクされうる場合、あるいは著作物がそれ自身ライブラリの場合特に重要である。これが真になるための閾値は法では正確には定義されていない。
もしそのようなオブジェクトファイルが、数字のパラメタやデータ構造のレイアウト、アクセス機構または小さなマクロや小さなインライン関数(長さが 10 行かそれ以下)のみ利用するならば、そのオブジェクトファイルの利用は、それが法的に派生物とみなされようとみなされまいと制限されない。(このオブジェクトコードに加えて『ライブラリ』の一部を含む実行形式は依然として第 6節の条件下に置かれるであろう)。
という部分です。 感染するかどうかは裁判所次第というとても微妙な線にあるのですが LGPL に感染する可能性があるだけで困る人もいるでしょうし 念のために template 部分は MIT LICENSE にしたのです。 ちなみに kgc.tar.gz と kgcpp.tar.gz を一つのライブラリに結合すると 全体が LGPL になるので再配布時には注意が必要です。
それではインストールの仕方です。 展開後のディレクトリで
./configure
make
sudo make install
としてください。 /usr/local 以下にインストールされます。 インストール先を変えるには
./configure --prefix=/home/kilrey/usr/local
というように指定してください。 その他のオプションは GNU autoconf/automake に準じます。
それでは利用法です。 超スマート・ポインタ に依存しているので そちらを先にインストールしてください。 実行時には libkgc.so と libpthread.so をリンクしてください。 gcc ならば -pthread を使うと良いと思います。 当ライブラリはヘッダしかないので kgc.hpp を include してください。 このとき kgc.h は自動的に include されます。
コードの書き方は
#include "kgc.hpp"
class target_t: public kilrey::kgc::with_child_t {
public:
kilrey::kgc::kfield_pointer_t<target_t> fptr;
void sweep(kvtable_callback_t callback, void* arg) {
fptr.pass(callback, arg);
}
};
int main() {
kcycle_init();
{
/* 実際の操作 */
kilrey::kgc::kauto_pointer_t<target_t> aptr(new target_t());
aptr->fptr = aptr;
}
kcycle_process_cycles();
kcycle_process_cycles();
kcycle_exit();
}
という感じです。 まず kcycle_init() を呼んで 循環参照解決用のメモリ領域などを生成します。 次に kilrey::kgc::kauto_pointer_t を 中身のポインタを引数にして生成します。 このとき kvtable_t は自動的に生成されます。 使用が終わったら循環参照を回収するために kcycle_process_cycles() を呼びます。 呼び出しの最後に循環参照を検出して 次の呼び出しの最初にその循環参照を解放するという仕組みです。 ある時点で確実に回収したい場合には 二回続けて呼び出すようにしてください。 最後に kcycle_exit() を呼んで 循環参照解決用のメモリ領域などを破壊します。
kilrey::kgc::kauto_pointer_t と kilrey::kgc::kfield_pointer_t との違いを説明します。 kilrey::kgc::kauto_pointer_t は 主に自動変数として使うスマート・ポインタで、 デストラクタで自分自身を kpointer_decrement() します。 また絶対に循環参照にならない条件ではメンバ変数として使うことも出来ます。 それに対して kilrey::kgc::kfield_pointer_t は kilrey::kgc::with_child_t のメンバ変数として使うスマート・ポインタで、 デストラクタで自分自身を kpointer_decrement() しません。 他から参照を受けている場合に循環参照の解決機構から 自動的に kpointer_decrement() されます。 このような循環参照になる可能性のあるクラスは全て kilrey::kgc::with_child_t を継承してください。 さらに循環参照になる可能性のある子ポインタは kilrey::kgc::kfield_pointer_t として持つとともに void kilrey::kgc::with_child_t::sweep() 中で 全ての子ポインタの kilrey::kgc::kfield_pointer_t::pass() を呼び出してください。 これにより循環参照の解決機構に子ポインタの存在を教えます。
注意としては kilrey::kgc::kauto_pointer_t と kilrey::kgc::kfield_pointer_t では自動型変換が無効になっています。 そのため
#include "kgc.hpp"
int main() {
kcycle_init();
{
/* 実際の操作 */
kilrey::kgc::kauto_pointer_t<target_t> aptr(new target_t());
kilrey::kgc::kauto_pointer_t<target_t> aptr1(aptr);//OK
//kilrey::kgc::kauto_pointer_t<target_t> aptr2 = aptr;//NG
aptr1 = aptr;//OK
}
kcycle_process_cycles();
kcycle_process_cycles();
kcycle_exit();
}
の OK のように正式にコンストラクタを呼ぶ初期化のみが使えます。 NG のように正式にコンストラクタを呼ばない初期化は使えません。 またその下の OK のように代入演算子は使えます。