boostの小道具いろいろ

boost C++ Libraries(以下単にboost)には、 mplやspiritみたいにやたらと気合の入ったでかいライブラリから、 ちょっとしたことに便利な小さなライブラリまでいろいろあります。 この記事では、細かいライブラリを紹介していこうかと思います。

checked_delete

必要なヘッダー: <boost/checked_delete.hpp>

C++では(Cでもですが)、不完全型(incomplete type)というものがあります。 詳細な説明はここではしませんが、一言で言ってしまえば「宣言だけされて定義がされていない型」 といったところでしょうか。 struct hogehoge { /* ... */ };のようにクラス(構造体、共用体)の詳細を定義しているのではなく、 struct hogehoge;のようにクラス名の宣言しかしていないような、アレです。 んで、C++標準ではこの不完全型へのポインタに対して、deleteする操作を認めています。

ところが、当然不完全型ですから、そのクラスのデストラクタやoperator deleteなんて知らないわけです。 C++標準では、デストラクタもoperator deleteもないクラスなら、正しくdeleteされるのですが、 どちらか一方でも存在した場合、deleteする動作は未定義となっています。

では、この未定義の動作は具体的にはどんな動作をするんだろうと思って調べてみると、 警告こそ出ますが、コンパイルには通ってしまいます(VC7.1で確認)。 コンパイラにしてみれば、不完全型なのでそもそもデストラクタなどがあるかどうかなど判らないのです。

そこで、そもそも不完全型のdeleteをできないようにしてしまおう、というのがこのライブラリです。 以下の関数とファンクタから成ります。

001 namespace boost {
002   template<class T> void checked_delete(T* p);
003   template<class T> void checked_array_delete(T* p);
004   template<class T> struct checked_deleter;
005   template<class T> struct checked_array_deleter;
006 }

checked_delete()関数は、不完全型のチェックをしつつdeleteを行います。 不完全型のチェックはコンパイル時に行われ、不完全型ならエラーを吐くようになっています。 また、コンパイル時にチェックを行うので、inline関数がきちんと展開されれば実行時のオーバーヘッドはありません。

checked_array_delete()関数は、new[]で確保されたメモリの解放を行います。 checked_(array_)deleter構造体は、その関数オブジェクト版です。

本来の目的とは違いますが、deleteを行う関数オブジェクトとして使うのもいいかもしれません。

current_function

必要なヘッダー: <boost/current_function.hpp>

__FILE____LINE__と同じようなマクロのシンボルです。 BOOST_CURRENT_FUNCTIONと書けば、現在の関数名に置換されます。 この機能は大抵のコンパイラが独自拡張で実装しているのですが、 コンパイラによってシンボル名がまちまちなので、 これを使うことによって移植性の向上が図れます。

boost_assert

必要なヘッダー: <boost/assert.hpp>

標準の<cassert>と同じように、アサーションを行うためのライブラリです。 プリプロセッサのシンボルを予め定義しておくことによって、

の3通りの動作を行います。

BOOST_DISABLE_ASSERTSが定義されている場合、アサーションは全て消去されます。 例によって、BOOST_ASSERTに副作用のある式を与えていると動作が変わってしまいますので、 副作用のある式は与えないようにしましょう。

BOOST_ENABLE_ASSERT_HANDLERが定義されている場合、 アサーション失敗時にユーザー定義の関数を呼び出すようになります。 呼び出されるのは、次のような関数です。

001 namespace boost {
002   void assertion_failed(const char* expr,
003                         const char* function,
004                         const char* file,
005                         long line);
006 }

これを、どこか適当なcppファイルで定義しておきましょう。 説明するまでもないかとは思いますが、 exprBOOST_ASSERTに与えた式の文字列表現、 functionはエラーの発生した関数名、 fileはファイル名、lineは行番号です。

以上2つのシンボルがいずれも定義されていない場合は、 ただのassertに置換されます。