handlename's blog

コード片など

boost::ptr_map の使い方

boost::ptr_mapの使い方が,どこを探してもはっきりとは載っていなかったのでメモ。 boostのバージョンは1.41。 必要最低限の使い方です。

下準備

boost::ptr_mapを使うためには,boost/ptr_container/ptr_map.hpp をインクルードする必要がある。

#include <boost/ptr_container/ptr_map.hpp>

また,説明するためにこんなクラスを用意。

/**
 * 基底クラス。
 * 純粋仮想関数を含んでいるのでインスタンスかはできない(インターフェイス)。
 */
class BaseContainer {
public:
	virtual void mes() = 0;
};

/**
 * コンテナクラス。
 * BaseContainerを継承。
 * 値の保持と,何を保持しているかを表示するメソッド。
 */
template <class T>
class Container : public BaseContainer {
private:
	T value;
	
public:
	Container(T value) {
		this->value = value;
	}
	
	void mes() {
		std::cout << "Container : value = " << value << std::endl;
	}
};

boost::ptr_mapインスタンスの生成

キーをstd::string,値を BaseContainer としてインスタンスを生成。 値を BaseContainer にすることによって, Container インスタンスにどんな型を指定しても おなじ ptr_map インスタンスに突っ込めるっていうすんぽー。

boost::ptr_map<std::string, BaseContainer> Map m;

値の追加

生成した ptr_map インスタンスに値を追加する。 ptr_map はキー・値ともに参照で渡さないといけないらしいので, 一度変数に落としてから渡すようにする。 インスタンスを渡す場合には直接 new してもOK。 直接 new しないと実行時にエラーになります。 元のインスタンスと,ptr_mapに追加したインスタンス(両方とも同じ場所を指してる)が, 終了時に両方とも解放されるのが原因なんじゃないかと。

// 一度変数に落とさないとコンパイルエラー
int key1 = 0; 
int key2 = 1;

// ポインタとして宣言して new する
// これをやると実行時に
// error for object 0x7fff5fbff260: pointer being freed was not allocated
// のようなエラーが出る(コンパイルは通る)。
// Container<int>* c;
// c = new Container<int>(10);
// m.insert(id1, c);

// 直接 new する
m.insert(id2, new Container<float>(20));

値の取り出し

boost::ptr_map インスタンスからオブジェクトを取り出す場合, std::map と同じように [] を使ってもうまくいかない。 扱ってるのがポインタだから?

// これだとコンパイルエラー
m[key1]

そこでメンバ関数の find() を使ってイテレータを取得してアクセスする。

// キー
m.find(key1)->first;

// 値
m.find(key1)->second;

// Container.mes() の呼び出し
m.find(key1)->second->mes();

値の削除

キーを指定して値を削除。 メモリの解放とかは勝手にやってくれるらしい。

// key1 の値を削除
m.erase(key1);

コードの全貌

今回のコードをつなげるとこんな感じになる。

#include <iostream>
#include <string>

#include <boost/ptr_container/ptr_map.hpp>


class BaseContainer {
public:
	virtual void mes() = 0;
};

template <class T>
class Container : public BaseContainer {
private:
	T value;
	
public:
	Container(T value) {
		this->value = value;
	}
	
	void mes() {
		std::cout << "Container : value = " << value << std::endl;
	}
};

int main() {
	typedef boost::ptr_map<int, BaseContainer> m;

 	std::string key1 = "n1";
 	std::string key2 = "n2";
	
	m.insert(key2, new Container<int>(98));
	m.insert(key2, new Container<float>(123.4));

	std::cout << m.size() << std::endl;

	std::cout << m.find(key1)->first << std::endl;
	m.find(key1)->second->mes();

	m.erase(key1);
	std::cout << m.size() << std::endl;

	return 0;
}

出力

2
0
Container : value = 98
1