[Top] > [Records March, 2004]

Platitudinous Records March, 2004

【<旧日記】【一覧】【新日記>】

● Mar. 16, 2004 (Tue.)

_boost::scoped_ptrを参考にしてこんなものを書いてみた.

class scoped_file { private: // noncopyable
	scoped_file(scoped_file const &);
	scoped_file & operator=(scoped_file const &);

	FILE *ptr;

public:
	explicit scoped_file(FILE *p = 0) : ptr(p) {}
	FILE * operator=(FILE *p) { this->reset(p); return this->ptr; }
	~scoped_file() { if (ptr != 0) fclose(ptr); }

	void reset(FILE *p = 0) {
		if (p != 0 && p == ptr) return;
		scoped_file(p).swap(*this);
	}
	void swap(scoped_file &b) {
		FILE *tmp = b.ptr;
		b.ptr = ptr;
		ptr = tmp;
	}
	FILE *get()      const { return ptr; }
	operator FILE*() const { return ptr; }
	operator bool()  const { return ptr != 0; }
	bool operator!() const { return ptr == 0; }
};

_使い方は言うまでもなくこうである.

{ // スコープ開始
	scoped_file out(fopen("test.txt", "wb"));
	fprintf(out, "test\n");
} // ここで自動的にfcloseしてくれる

_だがしかし用途がFILE *に限定されるのは非常にいただけない.できれば template<T> class scoped_obj; みたいな感じで,TにはFILE *でもHANDLEでもなんでも入れたいのである.が,しかしならが閉じる関数がわからない.閉じる関数は戻り値もまちまちだし,果てどうしたものかと悩んでいたところ,auto_closerなるものをみつけた.なるほど,戻り値はまちまちだがそれもテンプレート引数にとってしまえば良いのか.そして閉じるのだから引数はひとつだけで,なおかつそれは作成したオブジェクトであることはほぼ疑いようがない.だがこの方法の難点はわざわざコンストラクタ引数にcloseする関数を指定しなきゃならないところで,これではデフォルトコンストラクタが使えない.それにcloseする関数ポインタ分オブジェクトサイズが増えるのも気になる.いや,確かに別にどちらも大した問題ではないし実用上十分なのだが,ふとATLのソースコードでテンプレート引数にポインタを取っているのを発見したのである.なるほど,コンパイル時に決定するならポインタでもテンプレート引数にできるらしい.

_というわけで,こうしてみた.前述のauto_closerとは違い,std::auto_ptrではなくboost:scoped_ptrのほうを真似たので所有権移動の概念はないが,必要ならそのように書き直せばいいだけなのでこの際問題なかろう.

template <class T, typename R, R (*F)(T)>
class scoped_obj { private: // noncopyable
	scoped_obj(scoped_obj const &);
	scoped_obj & operator=(scoped_obj const &);

	typedef scoped_obj<T, R, F> this_type;
	T m_obj;

public:
	explicit scoped_obj(T obj = 0) : m_obj(obj) {}
	T &operator=(T obj) { this->reset(obj); return this->m_obj; }
	~scoped_obj() { if (m_obj != 0) (*F)(m_obj); }

	void reset(T obj = 0) {
		if (obj != 0 && obj == m_obj) return;
		this_type(obj).swap(*this);
	}
	void swap(this_type &b) {
		T tmp = b.m_obj;
		b.m_obj = m_obj;
		m_obj = tmp;
	}
	T get()          const { return m_obj; }
	operator T()     const { return m_obj; }
	operator bool()  const { return m_obj != 0; }
	bool operator!() const { return m_obj == 0; }
};

_最初に出したscoped_fileなら,typedef scoped_obj<FILE *, int, &fclose> scoped_file; としてやれば同じように使える.我ながらお見事.まあ無効ハンドルが0というのに限定してるのがなんともといえばなんともだが,大抵この手のWrapが必要なオブジェクトはポインタだろうし大丈夫だろう.まあ,必要になったらなったでテンプレート引数にINVALIDを付け加える挑戦をしてみるのも面白いかもしれない.とひとしきり満足したのだが,困ったことに以下のコードはコンパイルできない.

{
	// compile error: 'specialization' : 
	//   cannot convert 'BOOL (__stdcall *)(HANDLE)' to 'BOOL (__cdecl *)(HANDLE)'
	scoped_obj<HANDLE, BOOL, &CloseHandle> out(CreateFile("test.txt", /* 略 */));
	DWORD len;
	WriteFile(out, "test\n", strlen("test\n"), &len, NULL);
}

_それは何故か.CloseHandleの呼び出し規約が違うからである.悲しい.悲しすぎる.これはあまりにも悲しすぎる.悲しみに沈みつつも,一応こんなことをしてやれば一応動かないことはない.

BOOL cdecl_CloseHandle(HANDLE h) { return CloseHandle(h); } // global scope

{
	scoped_obj<HANDLE, BOOL, &cdecl_CloseHandle> out(CreateFile("test.txt", /* 略 */));
	DWORD len;
	WriteFile(out, "test\n", strlen("test\n"), &len, NULL);
} // CloseHandle

_しかしこれはいくらなんでもあんまりだ.あんまりすぎる.どうせ typedef scoped_obj<HANDLE> scoped_handle; とかやるんならそのときに一緒にWarpしてしまえというのであれば,まあ,それはそれでアリといえば,アリかもしれない.のだが.

● Mar. 17, 2004 (Wed.)

_ところで,昨日のscoped_objは実はVC6でコンパイルできない.というのはどうも template<class T, typename R, R (*F)(T)> で,第3引数のRとTが具体化されないようなのである.仕方がないので具体化するように入れ子にしてやればコンパイルできた.というか,時間軸的には先にこちらを書いたのだがまあそれは良い.キニスルナ.

template <class T, typename R> struct scoped_obj {
	template <R (*F)(T)> class close_func { private: // noncopyable
		close_func(close_func const &);
		close_func & operator=(close_func const &);

		typedef close_func<F> this_type;
		T m_obj;

	public:
		explicit close_func(T obj = 0) : m_obj(obj) {}
		T &operator=(T obj) { this->reset(obj); return this->m_obj; }
		~close_func() { if (m_obj != 0) (*F)(m_obj); }

		void reset(T obj = 0) {
			if (obj != 0 && obj == m_obj) return;
			this_type(obj).swap(*this);
		}
		void swap(this_type &b) {
			T tmp = b.m_obj;
			b.m_obj = m_obj;
			m_obj = tmp;
		}
		T get()          const { return m_obj; }
		operator T()     const { return m_obj; }
		operator bool()  const { return m_obj != 0; }
		bool operator!() const { return m_obj == 0; }
	};
};

_使うときはちょっと妙な構文だがこうである.

{
	scoped_obj<FILE *, int>::close_func<&fclose> out(fopen("test.txt", "wt"));
	fprintf(out, "test\n");
} // fclose

_だがそれでも,やはり呼び出し規約の問題は同じくして残る.というか先に書いたのは以下略.キニスルナ.で,まあ一応強引に解決しようとこんなコードを書いてみたりもした.

template <class T, typename R> struct scoped_obj {
	template <R (__cdecl *F)(T)> class cdecl_close {
		// 実装省略
	};

	template <R (__stdcall *F)(T)> class stdcall_close {
		// 実装省略
	};
};

_いや,まあ,要するにscoped_obj_stdcallとかも作るかという話なのだが.単に時間的にこちらを先に書いただけである.どうせtypedefするなら古いコンパイラでも通るこちらのほうが良いのかもしれないがまあ大差はない.

_なんにしろ,少なくともWindowsは呼び出し規約が付きまとう.STLのfunctionalはどうなってるのだろうと思えばどうやらこれでも呼び出し規約はデフォルト以外コンパイル時に引っかかるようである.なんとも.なんとか良いアイデアはないものだろうか.環境依存だしC++でどうこうというレベルの話ではないような気もするが.

● Mar. 22, 2004 (Mon.)

_DQ Vの主人公が持つのは剣ではなく杖なのだな,とかどうとか.それにしても懐かしい作品だ.わざわざ3Dにして書き直す必要があったのかどうかは謎ではあるが,果て,どちらかというと実験的な要素が強そうに見える.いや開発陣の思惑なんか知ったことじゃないが.

_買ってみたいが買ったところでやれんだろうなあ.FFTも途中だし.週末に少しずつ進んでたりとかはしてたんだがだんだん敵が強くなってきた.幾分強引な戦略で連戦突破したが,こう,なにかと下手な私はやっぱちゃんとLv上げとやらをすべきかもしれない.

_Fast Fourier Transformのことじゃないよ? ていうか乗算するのにFFTが出てきたのは割と困ったが.まあ別に無理に高速化せんとも乗算くらい筆算で十分だ.でも除算手付かず.allocatorも手付かず.ううむ.

● Mar. 26, 2004 (Fri.)

_そろそろマシンを新調しないとなと思って通販で注文したわけだが.よくよく見てみると一年前のスペックより軒並み低いというのは如何なものか.メモリ容量もHDD容量もきっかり半分.CPUは0.2GHzほど低クロック.GAはGeForce FX5200 128MBなのだそうだがこいつに関してはスペック差不明.サウンドはカード積んだとはいえ安物だし,LANはオンボードだし.オプティカルドライブもDVD+RW/+Rとか書いてあるが詳細みてないし良く分からん.ちなみに送料税込みで120k.ディスプレイとキーボードとマウスは今のを使うのでナシだが.まあメモリはでゅあるちゃんねるがどうとかこうとかで一年前のには劣らないと信じたいぞ.容量は半分だが.半分かよ.価格も半分じゃとんとんじゃねえか.

_まあ貧乏は貧乏なのだ.財政難なのだよ.それはともかく,NorthwoodとPrescottで1kだか2kだかくらいしか違わなかったんで新しい方がいいだろーという安直な考えでPrescottの方選んだんだがもしかしてこいつは失敗だったか.なにかと,性能差はほぼなし,消費電力と発熱アップ,とかどうとか良い話を聞かんわけで.もう少し調べてから選ぶべきだった雰囲気だな.ま,もう頼んじまったもん今更仕方ないけど.

_ところで色々あってまたHHK Lite2を買ってきのだが,帰ってきてから押入れをみたらもいっこHHK Lite2が出てきてなんだかなあ.みっつも同じキーボード持ってるなよって感じはひしひしとする.そいや前に買ったんだっけ.まああるもん使うつもりだがその前に掃除したいところだなキーボード.

_どちらかというとできればマウスの方が欲しい.チルトホイールつきのやつはダメだ.全然ダメ.許しがたい.一つ前のモデル返せ.かえせっつーの.CtrlもShiftも割り当てられんサイドボタンになんの意味がある.つかボタンの位置ずれて押しづらいしいやもうこんなボタンついとる価値ないがな! ホイールは横に動いたところで全然嬉しくないし前後回転はぬめりとしやがってなんつーか用途限定しすぎだっつの.まあ買っちまったもん使うなりなんなりしないともったいないんだが.ホイールやボタンの位置に関してはまあ慣れればどうにかなるかもしれないと期待するにしろ,そもそもボタンに押す価値がないのはとんでもなく問題だ.問題なのだよ.戻れたり進めたりして何が嬉しいんだ一体.一日中Webブラウザ使ってるのかと.しかも進んだり戻ったりして延々同じサイト見続けるのかと.実に理解に苦しむ.


【<旧日記】【一覧】【新日記>】
[Top] > [Records March, 2004]
管理者:Wayne mail address