上記の広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書く事で広告が消せます。

--.--.-- --:-- | スポンサー広告 | トラックバック(-) | コメント(-) |

C++のプログラミングで比較的大きなプロジェクトを扱ったときそれは突然発症し、
それこそガンのようにしつこく手を打つにも難しい問題がでてくる。
その一つが相互参照、あるいは循環参照。
今まさに直面していたり(´・ω・`)

よくあるサンプルで示すと
// ----- A.h -----
#include "B.h"
class A
{
public:
B b;
};

// ----- B.h -----
#include "A.h"
class B
{
public:
A a;
}

クラスAのメンバはBのインスタンスを持ち、かつクラスBはAのインスタンスを持つ。
こうなってはC++ではコンパイルできない・・・
そしてこれまたよくある解決法を示すと
// ----- A.h -----
class B; // 前方宣言(A::bのため)
class A
{
public:
B* b;
};

// ----- B.h -----
class A; // 前方宣言(B::aのため)
class B
{
public:
A* a;
}

includeをやめて前方宣言にし、ポインタを持たせるとすんなり通る。
cppでそれぞれのヘッダをincludeしてやり、ポインタをセットするメンバ関数を作れば問題なし。

・・・なのだが、僕の場合はもうすこし複雑な事情があって問題だらけに。
普通ならC++プログラムはソース(.cpp)とヘッダ(.h)で構成されているのだけど、
ヘッダひとつで宣言と実装を済ませて1クラス1ファイルにしているため、
ポインタからメンバを呼び出そうものなら上記のような解決法ではムリなのだ・・・
(だったら宣言と実装を分けろよって言われたらそれまでなんだけど)

本来、相互参照や循環参照はプログラムの設計そのものが間違っているからこそ
起きることが多いんだけど、世の中必要な相互参照もあるっちゃあるわけで。
機能別にカプセル化しようにも、条件に左右されやすい機能では条件の参照が必要に。
たとえば、BをAに委譲したとき。
(DoIt関数を使った自己委譲は無いものとする)
// ----- A.h -----
#include "B.h"
class A
{
public:
B b;
unsigned long m_uFlags;

A() { b.SetA(this); };
int DoIt() { return b.DoIt(); };
unsigned long GetState() { return m_nFlags; };
};

// ----- B.h -----
class A; // 前方宣言
class B
{
public:
A* pa;

void SetA(A* p) { pa = p; };
int DoIt() { return (pa->GetState() != 0) ? 100 : 50; };
};

例なので荒くざっくり書いたけど、結局エラーがでてコンパイルならず。
じゃぁどうしたらいいんだろう。
卑怯(?)なコードだとこうかな?
// ----- A.h -----
#include "B.h"
class A
{
public:
B<A> b;
unsigned long m_uFlags;

A() { b.SetA(this); };
int DoIt() { return b.DoIt(); };
unsigned long GetState() { return m_nFlags; };
};

// ----- B.h -----
template<class T>
class B
{
public:
T* pa;

void SetA(T* p) { pa = p; };
int DoIt() { return (pa->GetState() != 0) ? 100 : 50; };
};

ポインタを扱わなきゃいけない上にテンプレートorz
あああああああ まどろっこしい!!まどろっこC!!!!!
どのみち委譲なら継承しちゃってもかまわないよね!よね!!!!?

// ----- A.h -----
#include "B.h"
class A : public B<A>
{
public:
unsigned long m_uFlags;

unsigned long GetState() { return m_nFlags; };
};

// ----- B.h -----
template<class T>
class B
{
public:
int DoIt() { return (dynamic_cast<T*>(this)->GetState() != 0) ? 100 : 50; };
};

スッキリ。A.DoIt()も可能だし。
ただ、宣言と実装をまとめたいだけのためにテンプレートまで引っ張り出す必要ってあるんだろうか?
本当はAのデータをクラスCとでもして、A、Bから参照させたほうがベストなんだろうけど。
宣言と実装を分けるべきか、継承か委譲か、設計をどうするか、非常に悩ましい。

2010.08.16 10:39 | プログラム | トラックバック(-) | コメント(1) |

最近やる気がまったくでないわけで、それが暑さからくるかと言われたらNOで。
なにもまったく手につかないって由々しいので気分転換に映画「INCEPTION」見に行ったりね。

これ、なかなか面白かった。内容も意味もある意味「深い」上、やってることが
プログラムでいう再帰関数だなぁとか思いながら見てたよ。
各所で言われているように、見終わった後誰かと内容について議論できるような、
多少小難しいけれど濃いめなシナリオ。
でもなんというか、そういう話し相手になる人と見に行かないと意味ないんだよね・・・orz


UOからしばし離れてやる気充填のため、Cottonのソースなんかをいじくり。
今現在使っているVBScriptから借用したIRegExpでベンチをとってみると・・・遅い。
すんごい遅い。マクロの処理が重いのはこのせいかぁ。
C++で正規表現、しかもUnicodeで扱うとなると選択肢はかなり限られるわけで、
他の正規表現ライブラリを使おうと鬼車ライブラリとにらめっこしたり。
イマイチ好きになれないんだよね、外部ライブラリに頼るの。
なにかいいものないかなと探してたところ、ありましたよ。
UnicodeもOKで将来性もあって高速なのが。

std::tr1::regex君。

テンプレートで文字列をコンテナとして扱えるので臨機応変だし
C++0xの一部として盛り込まれてるので安泰だ。
Ollyさんで見る限り特殊なランタイムもいらないし、最高。
とりあえず自分用メモでも張って満足感に浸ろう。
#include <tchar.h>
#include <iostream>
#include <string>
#include <regex>
using namespace std;
using namespace std::tr1;
#ifdef _UNICODE
#define _tcout wcout
#else
#define _tcout cout
#endif

int _tmain(int argc, _TCHAR* argv[])
{
// 正規表現のコンパイルとマッチ結果用変数
basic_regex<TCHAR> rx(_T("abc(.+)abc"));
match_results<const TCHAR*> mr;

// 完全一致か確認 regex_matchをregex_searchに置き換えると部分検索になる(1ヒットのみ)
bool bMatched = regex_match(_T("abcdefabc"), mr, rx);
if (bMatched)
{
_tcout << _T("regex_match: matched_string=") << mr.str(0);
_tcout << _T(" $1=") << mr.str(1);
_tcout << _T(" $1.begin=") << mr.position(1);
_tcout << _T(" $1.end=") << mr.position(1) + mr.length(1) << endl;
}

// 置換
basic_string<TCHAR> strText, strFmt, strResult;
strText = _T("abcdefabc abcghiabc");
strFmt = _T("_$1_");
strResult = regex_replace(strText, rx, strFmt);
_tcout << _T("regex_replace: replaced_string=") << strResult << endl;

// すべての一致結果列挙
regex_iterator<basic_string<TCHAR>::const_iterator> rxi(strText.begin(), strText.end(), rx);
regex_iterator<basic_string<TCHAR>::const_iterator> rxi_end;
for(; rxi != rxi_end; ++rxi)
{
_tcout << _T("regex_iterator: matched_string=") << rxi->str(0);
_tcout << _T(" $1=") << rxi->str(1);
_tcout << _T(" $1.begin=") << rxi->position(1);
_tcout << _T(" $1.end=") << rxi->position(1) + rxi->length(1) << endl;
}

return 0;
}

2010.08.05 16:50 | プログラム | トラックバック(-) | コメント(2) |

先日のイベントで花火Qスタがもらえるようになったらしい。
各シャードごとに色が違い、ここ大和ではきれいな青。
イベント当日はログインできなかったので、どんなことが起きていたのかさっぱりだけど、
貰えるものは貰っておかないとね。
ブリ城に配布用の箱が設置してあったよ。
100711_00.jpg

この花火Qスタには種類があるらしく、使用するとそれぞれ5ch/13ch/29ch/49ch消費し、
その消費数に応じた派手さの花火があがる模様。
消費量は杖ごとに決まっていて、箱を引いたときにランダムに決まるみたいだね。
さらに同じチャージ消費量の杖であっても、花火を射出する速度にも違いがあるようで、
細かく数えたら何種類になるのかわからない。
(派手さに加えて速度、あるいはパターンが杖ごとに記憶されているんだと個人的に解釈)

6キャラで貰ったうち3つは49chタイプで、速度もそれぞれ違うものをゲットできたので満足。
そして5chタイプの杖を持て余したので、物は試しとAshで叩いてみた。
・・・できちゃった
100711_01.jpg

錬成も普通にできるようなので、余った花火Qスタはメイサーの特攻武器として使おうかなぁ。
チャージも回復するし、錬成の初期不安定度も0なのでなかなか楽しめそうな花火Qスタだね〜

2010.07.11 07:05 | UO | トラックバック(-) | コメント(0) |

最近UOネタに乏しいので日常のあれこれも記事に付けていこうと思い、
さくさくリンクさんに【UO】タグのフィルタリングをお願いしたり。
他ブログの方みたいにハッスルできるほど交友が広くないので、ほんとネタが見つからない作れない。
ただの不定期日記なので記事を書く必要性は全くないけど。

これから夏真っ盛り暑い日差しが続きそうなのに、そんな中でエアコンの室外機故障が発覚。
現在、マシンの排熱に耐えつつ扇風機のお世話に。すばらしい科学力だ。
時期が時期だけに電気屋さんもエアコン取り付けの予約がみっちりらしく、
ものすごい蒸し風呂状態になろうと、扇風機一つで耐えていかなくちゃいけない・・・
ヘルシーな蒸し料理になってしまうのも時間の問題。おいしく食べてね。


そういえばカップヌードルのCMだったかで初めて下の曲を知ったよ。

Jamiroquai - Virtual Insanity
100705_00.jpg


曲の感じといいPVといい、ものすごいインパクトで、とても14年前の曲とは思えない・・・
これを超えるPVって無いんじゃないかなぁ。個人的に。
「え、Jamiroquai知らないの?」
ってちょっと小馬鹿にされかけたので、相当有名な曲だったんだね((((;゚Д゚)))
お気に入りの曲なんてCMでしか出会えないものだとおもうよ・・・。
今回はそれがたまたまカップヌードルだっただけで。
ちなみにカップヌードルたべると100%お腹こわすので怖くて食べれませんヨ。

2010.07.05 20:05 | 日常 | トラックバック(-) | コメント(2) |

先日のUOCooler、思いのほか反響があってうれしい限り。
>>157さんにあっという間に届いたのには驚いたけど、ちゃんと効果が出てるようなのでヨカッタ。
そしてちらちらと上がっているお声に反応してみる。


>これはログイン画面の時だけ効果が出る?
>ログイン後は効果が無いってこと?

UOのパッチチェック、ゲーム本体の起動から終了まですべて効果デルヨ!!
なのでしっかり発熱をおさえてうるさいファンの音ともおさらばできる「はず」なんだ。
うちはファンコンでファンの回転数が固定なので実感しようがないヨ。


>i7 860だと効果無いみたいヨ。
>個人的にはインストーラ形式じゃない方がいいヨ。

うーん、クーリングの実装はCPUを選ばない単純な方法で行っているので、動かないのは悔しい・・・
あと、確実に動かすためには、
・UOCoolerを先に起動しておく(スタートアップ推奨)
・UOの実行ファイル名を変えていない
・管理者権限で実行されている
くらいしか思いつかないTT
インストーラなのは、温度を下げたいけどソフトをどうやって毎回起動できるように
設定するかわからない、っていう方のために採用したよ。
僕もインストーラはキライなのでよくわかる・・・


>スタートアップにあんまりソフトいれたくないヨ。
>2Dクライアントと一緒に起動されるほうがうれしいヨ。

一応、UOを起動するときだけ効果が出る・・・というよりUOを自動起動するタイプをつくってみたよ。
クーリングが有効になると左上のアイコンが青色に変化。
トレイではなくUOのウィンドウに設定メニューがでる形に。
100701_00.jpg

UOCooler.exeを実行するとレジストリにあるUOの場所を参照して自動起動するんだけど
UOをちゃんとインストールしていない環境だと起動できないかも。
そしてもう一つ、VirusTotalで最終チェックをしてみたところ、McAfee-GW-Editionの
ヒューリスティック機能が誤認識するようだ。
100701_01.jpg

v1.0がグローバルフックなのに対し、v1.1はプロセスを絞って負荷抑制コードを書き込んでるので
CodeInjectionとして認識されるのも仕方ないかなぁ。
表記が「Heuristic.BehavesLike.Win32.CodeInjection.H」なので間違ってはいないけどね。


というわけで、スタートアップ&インストーラが嫌いでスマートに使いたい、
それでいて上記の意味が理解できる方のみこちらからダウンロードしてくださいませ。
とくに大きな理由がない限りは通常版を使ってください。

[01:13追記]
2点変更を加えたのでzipを差し替えました。
・レベル設定が背面に回らないように変更。
・設定を変更したときにごく稀に一定時間クーリングが無効になるバグの修正。

2010.07.01 20:45 | プログラム | トラックバック(-) | コメント(0) |