亀岡的プログラマ日記

京都のベッドタウン、亀岡よりだらだらとお送りいたします。

C++/CLIの使い方 超基本を今更おさらい。

先日書いたように、業務でC++/CLIを使いそうなので、その準備も兼ねてお勉強中です。とりあえず、超簡単なサンプルで呼び出しまではできるようにしたので、そこらへんをメモがわりに書いておこうかと思います。

超簡単サンプル概要

プロジェクトは超シンプルです。受け取った文字列に”Echo”と書き加えて返してくれる、というだけのクラスをネイティブ側で実装し、それをC++/CLIでラッピング。さらにそれをWinFormから読んでみます。
f:id:posaunehm:20120108015401j:image

はまったところ

ポインタでしかC++のクラスは持てない

そうなんですよね。C++のプロジェクトで作っているクラスのメンバをC++CLIでは持つことはできません。ポインタなら持てます。まあ内部的にはIntPtrで持てるからってことなのでしょう。

文字列変換周り

とりあえず今回はstd::stringとの相互変換のみ。これはもう全面的にこちらを参考にしてます。

というわけで以下のような感じなコードがC++CLIに出現します。m_pNativeClassというメンバにネイティブで実装下側のポインタが入っています。

		String^ Echo(String^ str)
		{
			std::string in;
			IntPtr mptr = Marshal::StringToHGlobalAnsi(str);
			in = static_cast<const char*>(mptr.ToPointer());
			Marshal::FreeHGlobal(mptr);
			std::string out = m_pNativeClass->Echo(in);
			return gcnew String(out.c_str());
		}
デストラクタとファイナライザの書き方

まず大前提として、C++/CLIで作ったクラスは何もしなくてもIDisposableを継承します。というのも、C++CLIのデストラクタ(~HogeClass()みたいな書き方をするメソッド)は、C++CLIの世界ではDIsposeメソッドを呼ばれた時に呼ばれることになっています。そいじゃC#で~HogeClass()で書くデストラクタはC++CLIでは!HogeClass()という書き方をし、そしてこれの名前はファイナライザと呼ばれます。
つまり

  • C#のDispose → C++CLIのデストラクタ
  • C#のデストラクタ → C++CLIのファイナライザ

ということになるようです。

分かりにくいですが、はっきりしているのはアンマネージドなリソースを使っている場合、解放すべき場所はデストラクタではなくファイナライザです。デストラクタだけにdeleteのコードとかを書いちゃうと目も当てられない感じにメモリリークしますよ。定石的書き方(C#のDisposeパターンと等価)はこうらしいです。

		Class1()
		{
			nativeClass = new CNativeClass();
		}
		~Class1()
		{
			//マネージリソースは特に無いので無視
			//ファイナライザ呼び出し
			this->!Class1();
		}
		!Class1()
		{
			//アンマネージリソースの方付け
			delete nativeClass;
		}

とりあえずこれで綺麗に使えてるっぽいです。しかしDisposeパターンをいまいちよくわかってないのですよね・・・。これは連休中に確認しておきます。。。