2006年11月27日

boost::lambda

先日のboost::bindのサンプルコードは、 boost::lambdaを使うことによりもうちょっと分かり易くなるようです。

以下のboost::bindを使ったコード(using namespaceを使って見やすくしました)は、

using namespace boost;
ItemList::iterator s = std::find_if(Items.begin(), Items.end(), bind(std::equal_to<int>(), bind(&Item::GetValue, _1), 10));
boost::lambdaにより、以下のようになります。
using namespace boost::lambda;
ItemList::iterator s = std::find_if(Items.begin(), Items.end(), bind(&Item::GetValue, *_1) == 10);

若干短くなり、==など見慣れた演算子が登場して分かりやすくなりましたね。・・・っていうかなんでこれ動くの・・・。

boost::lambdaのより変態的なサンプルを見たい方は、以下のページがお薦めです。
Entangled Space boost user - lambda

2006年11月26日

boost::bind

boostのbindを使った感想とサンプルコードを書きます。

以下ような、整数値を一つ格納できるItemというクラスと、Itemクラスへのポインタ(boost::shared_ptr)を要素としたItemList型、そしてItemList型のオブジェクトItemsがあったとします。

class Item
{
public:
  int GetValue(void) const
  {
    return Value_;
  }
private:
  int Value_;
};

typedef std::list<boost::shared_ptr<Item> > ItemList;
ItemList Items;

Itemsに格納されているItemオブジェクトのうち、GetValue()で取得できる値が10となっているItemオブジェクトのイテレータを取得するコードは、次のように書けます。

ItemList::iterator s = Items.begin();
for (ItemList::iterator e = Items.end(); s != e; ++s) {
  if ((*s)->GetValue() == 10) {
    break;
  }
}

このループは、boost::bindを使うと以下のように1行になります。

ItemList::iterator s = std::find_if(Items.begin(), Items.end(), boost::bind(std::equal_to<int>(), boost::bind(&Item::GetValue, _1), 10));

boost::bindすげぇ。templateマジックです。素晴しいです。
boost::bindをもっと使いこなせば、かなりの処理を一行で書いてしまえそうです。

しかし、boost::bindを使いすぎると分かり難いコードになりそうです。メンテナンスの容易さが問われるときは、分かり易いfor文を使うことを検討してみるのも良さそうです。

(2006/11/27) このコードはboost::lambdaによりもう少し見やすくなります。詳しくは続きで。

2006年11月24日

シングルトンとマルチスレッド

C++のSingletonパターンの実装のうち、有名なものの1つとして、以下のようなローカルstatic変数を使った実装があります。

class Foo
{
public:
  static Foo& GetInstance(void);
};

Foo& Foo::GetInstance(void)
{
  static Foo Instance;
  return Instance;
}

最近、この実装がスレッドセーフではないことに気が付きました。
そんなの当たり前だろ!と突っ込まれそうですが、スレッドセーフか?と疑ったことが無かったので気が付きませんでした。

このコードがスレッドセーフにするためには、コンパイラは以下の点を守るようならなければなりません。

  • Fooのコンストラクタを2回呼び出さない。
  • Fooのコンストラクタが実行し終わるまで、他の関数を呼び出さない。
まあふつーに無理そうですね。実際に無理のようです。

代わりにデファクトスタンダードなSingletonライブラリを使おうかと思ったのですが、 デファクトスタンダードな代物が見つからず・・・。boostにあると思ったのですが、 boostのSingletonクラスはboost::details::pool::singleton。poolのおまけみたいです。
どれを使うべきか良く分からなかったので、とりあえず複数スレッドを起動する前にインスタンスを生成してしまうことにしました。お終い。

しかし、 「C++ Singleton」で検索したり、 「boost Singleton」で検索したりすると分かるのですが、Singletonの実装って奥が深いようですね。正直近寄りたくないくらいに・・・

以下、参考情報です。

2006年11月21日

_bstr_tとwstringの相互変換

文字列クラス_bstr_tとwstringの相互変換のお話です。
開発環境は Visual C++.NET 2003 です。

_bstr_tはBSTR型のラッパで、COMサポートクラスの1つです。COM スマートポインタなどと一緒に使うととても便利です。 Visual C++からMSXMLを使うときは手放せないクラスです。

wstringはwchar_tを要素とするC++標準ライブラリの文字列クラスです(正確にはtypedef basic_string wstring)。 どちらの文字列型も1文字16bitで、Unicodeを格納して使います。
_bstr_tは、COM周りでよく使います。wstringも、標準なので他のライブラリで使うことがありますし、_bstr_tよりも機能が豊富なのでCOMに触れないときはこちらを使いたいのです。 そこで、_bstr_tとwstringを相互に変換したいというお話が出てくるのです。

以下本題です。

wstringから_bstr_tへの変換コードは以下の通りです。

std::wstring wstr(L"WSTR");
_bstr_t bstr(wstr.c_str());

こちらは簡単ですね。

ちょっと厄介なのが_bstr_tからwstringへの変換です。

_bstr_t bstr(L"BSTR");
std::wstring wstr(bstr);

このコードであれば問題ないのですが、次のコードが問題となります。

_bstr_t bstr;
std::wstring wstr(bstr);

_bstr_tが空だと問題になるのです。私の環境では、これを実行すると次のエラーがでて強制終了してしまいました。

XXXX.exe の 0x00XXXXXX でハンドルされていない例外が発生しました : 0xC0000005: 場所 0x00000000 を読み込み中にアクセス違反が発生しました。 。

かなり問題があります。_bstr_tが空のとき、_bstr_t::operator const wchar_t*()がNULLを返すことが原因のようです。
私は、以下の関数を使って対策することにしました。

const wchar_t* safety(const _bstr_t& arg)
{
  return !arg ? L"" : arg;
}

使い方は変換前にはさむだけです。

_bstr_t bstr;
std::wstring wstr(safety(bstr));

_bstr_tからwstringに変換するときにいつもsafetyを使うよう心がけていればこれでOKです。 本当は、いつも何かを心がけるなんて面倒ですし間違えやすいので、safety関数を使わなくても問題がないようにするか、safety関数を使わないと_bstr_tからwstringへ変換できないようにするべきです。しかしこれについては解が見つかりませんでした。残念。

2006年11月14日

デジカメ画像+トラックログ

GPS-CS1Kを使ってデジカメ画像とトラックログの両方をGoogle Earthに表示するお話です。
「GPS-CS1K+Google Picasa+Google Earth その2」という記事に書いた、Google Earth上にデジカメ画像を表示する方法と、
「GPS-CS1K+Google Earth+GPSBabel」という記事に書いた、Google Earth上にトラックログを表示する方法を組み合わせます。

上記2つの記事の通りに作成したkmzファイルとkmlファイルを、Google Earthで開いてみましょう。
メニューのファイル→開く で開くことができます。
これで完了です。以下のように、デジカメ画像とトラックログの両方が表示されます。素晴らしい。
Google Earth

場所ウィンドウの中の「保留」という項目を右クリックし、名前を付けて保存を選択すると、このデータを保存できます。kmz形式で保存しましょう。
Google Earth Save

保存したkmzファイルには画像まで一緒に詰め込まれていますので、データを公開するときはkmzファイルだけを公開すれば十分です。
参考までに、上記のスクリーンショットを取るために使ったデータをダウンロードできるようにしておきました。ご覧になりたい方はGoogle Earthで開いてみて下さい。
デジカメ画像+トラックログ詰め合わせ kmzファイル ダウンロード

2006年11月13日

GPS-CS1K+Google Picasa+Google Earth その2

GPS-CS1K、Google Picasa、Google Earthを連携させる話の続きです。
以前のやり方よりも良い方法を見つけましたので、それを紹介します。

Google Picasaのメニューから以下のようにTools→Geotag→Export to Google Earth Fileを選択します。
Picasa with web sharing

こうすると拡張子がkmzのファイルを出力することができます。こうしておくと、Google EarthのGUIがだいぶスマートなものになります。

このkmzファイルを開くとGoogle Earthが起動します。
Google Earth
表示されているのはデジカメ画像のサムネイルだけです。以前のGUIと比べてだいぶすっきりしました。

サムネイル画像の上にマウスカーソルを置くと、ちょっと大きいサムネイル画像と、ファイル名が表示されます。
Google Earth マウスカーソルon

サムネイル画像をクリックすると、同じ場所で撮った画像をこのように並べてくれます。
Google Earth マウスクリック
この場所ではもっとたくさん画像を撮ったんですけど、なぜか4つだけです。位置情報が微妙に違うからかもしれませんが、改善して欲しいところです。

さらにサムネイル画像をクリックすると、大きめの画像が表示されます。
Google Earth 画像拡大

だいぶスマートなGUIです。フルサイズの画像表示へスムーズに繋げられるともっと良いですね。

なお、このkmzファイルは、画像まで一緒に詰め込まれていますので、そのまま人に渡すこともできます。
上記のスクリーンショットを取るために使ったデータをダウンロードできるようにしておきましたので、ご覧になりたい方はGoogle Earthで開いてみて下さい。
GPS-CS1K体験用 kmzファイル ダウンロード

2006年11月12日

NOD32とApache2の相性問題

我が家のサーバは、OSがWindowsXPで、WebサーバはApache2です。
これに「NOD32 アンチウイルス V2.5」をインストールしてみたところ、Apache2が頻繁におちるようになりました。一週間に一回位落ちます。
エラーメッセージその他を見る限り、NOD32とApache2の相性が悪いようです。

NOD32をご利用の方は、お気をつけ下さい。

ちなみに他のPCでもNOD32を使っているのですが、こちらは全く問題ありません。Apache2と組み合わせなければ良いようです。

2006年11月08日

GPS-CS1K+Google Earth+GPSBabel

今回は、GPS-CS1K、Google Earth、GPSBabelを連携させてトラックログを表示させるお話です。
参考記事は、ESCAPE WHILE YOU CAN: GPS-CS1Kです。

Google Earthは、GPSデータをもとに、歩いた道のりを線で表示させることができます。
しかし、GPS-CS1Kが出力するGPSデータの形式(NMEA-0183)にGoogle Earthが対応していないので、すんなりとは行きません。一度Google Earthが受け取ることができる形式(KML形式)に変換する必要があります。

この変換はGPSBabelというツールで行えます。GPSBabelはGPSBabel Homeからダウンロードできます。私はWindows用のgpsbabel-1.3.2.zipというアーカイブファイルをダウンロードしました。

GPSBabelはコマンドライン版(gpsbabel.exe)とGUI版(GPSBabelGUI.exe)があります。
私はGUI版を使いました。
以下のようにNMEA-0183からKMLに変換するように設定してlet's goボタンを押せば変換完了です。
GPSBabel

拡張子をkmlにしておけば、変換後のファイルを開くだけでGoogle Earthが起動して道のりが表示されます。
Track on Google Earth

私が歩いた道のりが表示されました。なんとなく感動しましたが、残念ながら3箇所ほどおかしいところがあります。

まずここはおかしいです。正解を赤線で書いてみました。なんかとんでもないところ入っていることになっていますね。
Error on Google Earth #1

お次はここです。何往復かしたように見えますが、一回通っただけです。
Error on Google Earth #2

最後におかしいところはここです。大ハズレです。橋も無いのに堀や川を横断しています。
Error on Google Earth #3

でもここ以外はかなり正確です。歩いた道を正確になぞっていますし、かなりうろうろしていた天守閣周辺もそのまま表現されています。
感想としては良いところ悪いところ半々くらいですね。悪いところ(大ハズレのところ)が発生する回数を運用で減らすことができれば、散歩のトラックログ記録用としてもかなり役に立つでしょう。

2006年11月07日

GPS-CS1K+Google Picasa+Google Earth

今回は、GPS-CS1K、Google Picasa、Google Earthを連携させる話です。

Google Picasaは、タダのPicasaではなく、Picasa with web sharingという代物を使う必要があります。
これは、Picasa Web Albumsから無料でダウンロードできます。英語版でしかもβ版です。入手にはGoogle Accountが必要です。
このPicasaの日本語版はまだ無いようです。

Google Earthは普通に手に入るもので問題ありません。ダウンロードはGoogle Earth ホームからできます。

連携手順は以下の通りです。
(1) GPS-CS1Kの付属ソフトを使い、デジカメ画像のExif情報にGPS-CS1Kから取得したGPSデータを埋め込みます。GPSデータを埋め込んだ画像は、どこかのフォルダにまとめて置いておきます。

(2) Google Picasaを起動し、画像が置いてあるフォルダを選択します。

(3) Google Picasaのメニューから以下のようにTools→Geotag→View in Google Earthを選択します。
Picasa with web sharing

(4) Google Earthが勝手に起動しますので後は自由に拡大縮小して楽しみましょう。
大阪城公園で撮ったデジカメ画像はこんな感じになりました。
Google Earth

誤差は10m~20m程度でしょうか。歩いた道がはっきり分かります。結構感動です。このくらいの精度があれば、普段のお散歩でも十分に役に立つでしょう。
測位準備中の状態が長いように感じたのでちゃんと測位できているか心配だったのですが、たいして問題なさそうです。対策(GPS-CS1Kをカバンに固定するなど)を取るともっと誤差が少なくなるのかもしれませんが。

ほとんどのデジカメ画像は正確な場所に表示されているのですが、一部GPS-CS1Kのエラーらしきものがありました。これです。
GPS-CS1Kのエラー?
img26とimg28を撮影したのはほとんど同じ場所ですが、200m程度離れているように見えます。なんででしょうね?

また、Google EarthのGUIはいまいちです。上記のスクリーンショットを見ても分かりますが、一言で言うと見難いです。img6,img7などの謎のイメージ番号(ファイル名ではないです。意味不明)が表示されていてうっとおしいです。デジカメ画像は小さくて見難いです(拡大表示ができません)。デジカメ画像と背景の色が似ているとどこに写真があるのか良く分かりません。
とりあえず見て楽しむ程度はできますが、今後これを使ってデジカメ画像を管理していく気にはなりません。改良待ちですね。

正直GPS-CS1Kの精度がここまであるとは思っていませんでした。蝶の出現ポイントを押さえることもできそうです。ハードウェアとしては満足しました。
ソフトウェアの方はまだ満足な解は見つかっていません。模索中です。GPS-CS1Kの出力データが標準フォーマットのデータなので、選択肢が山ほどあるのがありがたいですね。いざとなったら自分で・・・というのもありですし。

2006年11月04日

GPS-CS1K

SONY GPSユニット GPS-CS1K」を買いました。
GPS-CS1K

この製品は人気があって入手困難なのですが、ヨドバシカメラで注文したら、4日ほどで届きました。
「ご注文を頂きましてからお届けまでに1ヶ月ほどお時間を頂戴致します。」って書いてあったんですけどね。不思議。

早速フィールドテストをしてみました。場所は大阪城公園。意味もなくうろついて適当に写真を撮ってきましたの。その後、GPS-CS1K付属の地図ソフト(Super Mapple Digital Ver.7)を使って、地図に写真を貼り付けてみると、こんな感じになりました。
大阪城公園

自分で撮った写真を地図に貼り付けることができるというのはちょっと感動ですが、六ヶ所にまとめられちゃっているのがちょっと残念です。
緯度や経度の情報はどの写真も違うので、地図ソフトの方の仕様でしょう。地図ソフトを選べば改善するかもしれません。

GPSユニットは、カバンにぶら下げておいたのですが、ふと見たときは測位準備中(測位できていない状態)の時が多かったです。
マニュアルを良く読んだら「本機を持ち歩く場合、アンテナ部分が上又は外側を向くようにして固定して下さい。」という注意書きがありました。
固定させていなかったのでこのせいかもしれません。次は固定させて使ってみることにします。

このGPSユニットが連携できるソフトは多いので、色々と試してみたいと思います。

参考リンク