S.F. Page

Programming,Music,etc...

スマートポインタへの参照

スマートポインタへの参照の使いみち・使いどころって何だろう?と考えていた。

例えばstd::shared_ptrは、参照カウント方式であり、参照カウントの加算・減算がコピー時に発生する。「std::shared_ptrのスレッド間コピーはスレッドセーフ」 が既定となっている。なので比較的重い処理とされている。std::shared_ptrは参照カウンタの加減算は必ずスレッドセーフで行われる。Boostのshared_ptrではBOOST_SP_DISABLE_THREADSを定義することで無効にできるとのこと。

なんかこういうところでコストがかかると知ると、shared_ptr間のコピーが気になりできる限りコストを削減できる方法はないかなと考えたりする。かと言って自分のアプリのパフォーマンスをQPFとか使って計測しているかというと、面倒なのでやっていないいい加減さだが。まあでも今作ろうとしているMIDIシーケンサとかはパフォーマンスを気にする方のアプリなのでそのあたりきちんとしないといけないのだが。きちんとするのは嫌だがキチンとせざるを得ない心境である。

話を戻すと、コスト回避の方法は2つあると思う。1つ目はできる限りunique_ptrを使えるところは使うということ、2つ目はshared_ptrの参照を使い、参照カウンタ演算を回避するということ。1番目はshared_ptrそのものの使いどころを考えるということで、2番目の方法は本末転倒な感じもするがshared_ptrの参照の安全な使いどころを考えるということでもある。

もともとなぜshared_ptrが必要なのかというと、shared_ptrが保持しているリソースを複数のオブジェクトで共有する場合に、共有されている限りはリソースを破棄されないようにするためにある。たとえばAがBというオブジェクトを作り、BをCも利用するというケースを考えると、A・Bが存在する限りCは存在しなくてはならない。こういう場合にshared_ptrは使える。CをA・Bはshared_ptrで保持するようにすればA・Bが任意のタイミングで破棄されようがA・Bのいずれかが存在している限りCの存在は保障されるのだ。ただCはA・Bの双方に依存しないというのが前提だけれども。つまりA・Bの生存にCが依存するのでshared_ptrが必要なわけで、それ以外の部分、つまりA・Bの生存に依存しない部分であれば参照は使えるような気がする。たとえばフリー関数の引数にCを渡し、関数内ではCの生存・破棄などを行わなくCをただ参照するのみであれば、shared_ptrの参照でもよいように思う。しかしただの参照だと保持しているポインタを改変できてしまうのでconst参照にすべきだろう。