文字列を走査したりするのに、char *p, *qとかして、二つのポインタを用意したりはよくする方法。
そうすれば、qが指すアドレスを変更してもpは文字列の先頭を指したまま。
配列をポインタで操作する時に、一時的にポインタの指すアドレスを操作してから、再度先頭のアドレスに戻すという事はよくある。
関数にポインタを渡して、関数内で処理すると、アドレスのコピーが渡されるので、明示的に元に戻す必要はない。
void print (char* p)
{ std::cout << p << std::endl;
}
void func1 (char* p, int offset)
{ p += offset;
print ( p ); // “lo, world.”
}
void func2 (char** p, int offset)
{ *p += offset;
print ( *p ); // “, world.”
}
int main ()
{ char* str = “hello, world.”;
char *p, *q;
p = q = str;
++q;
print ( p ); // “hello, world.”
print ( q ); // “ello, world.”
func1 (p, 3); // “lo, world.”
print ( p ); // “hello, world.”
func2 (&p, 5); // “, world.”
print ( p ); // “, world.”
return 0;
}
関数で処理したアドレスを元のポインタにも反映させたい場合にはポインタのポインタを渡せば可能。
オブジェクトの場合。
もしテーブルが閉じていたら開く。
もしテーブルが開いていたらそのままにする。
処理が済んだら元の状態に戻す。
というような事もよくありますが、結構戻すのを忘れちゃったりするので、それ用のオブジェクトを作成してコンストラクタで保存した値をデストラクタで元に戻す。
class recall
{
private: bool active;
TABLE* table;
public: recall (TABLE* tbl) : table (tbl)
{ if (tbl == NULL) return;
active = tbl->is_active ();
}
virtual ~recall ()
{ if (table == NULL) return;
table->set_active (active);
}
};
このrecallオブジェクトをTABLEオブジェクトの変更前に作成しておけば、スコープから抜ける時にデストラクタが実行されてactiveをもとに戻してくれる。
void update (TABLE* tbl)
{ recall active_recall (tbl);
tbl->set_active (true);
… 何かの処理 …
}
void main ()
{ TABLE* table = new TABLE ();
table->set_active (false);
update (tbl);
delete table;
}
と、これで、update関数から抜ける時にスコープから外れるのでactive_recallオブジェクトが破棄され、デストラクタが実行されるので、activeが再びfalseに設定される。
VCLには今参照しているポインタを破棄してリコールを無効にするForget、今参照しているポインタを返すReference、 現在の状態を保存するStoreという関数を持ったTRecallが存在し、派生クラスとしてはTFontRecall、TBrushRecall、TPenRecallなどが用意されている。
動的に書体を変更したいようなOnDrawCellのイベントハンドラなんかでスマートポインタと一緒に使うと安心。
普通にnewしてtry&__finallyでdeleteしてもいいんですけど、deleteを忘れないなら__finallyで元に戻せばいい事なので、やっぱりスマートポインタを使った方が効果が大きいような気がしますし、一貫してる気がします。