C++オブジェクトを dispatch_async越しに渡すのにstd::shared_ptrを使うでござる

C++クラスのオブジェクトを dispatch_async 越しに渡したい。
たとえばこんな風に。

しかしこのようにC++オブジェクトそのものを渡すと、それは値渡しになる。
つまりコピーが渡されれる。
つまり元の cppObj とブロック内の cppObj は別インスタンスになる。
しかもblock内はconst扱い。
しかも何故かコピーコンストラクタが2度呼ばれる。。。たぶん、ブロックにキャプチャされた時に1回、dispatch_asyncでブロックがコピーされた時に1回、計2回ですね。。
CPPClassが (x,y)の2次元ベクトルのような小さなクラスであれば問題ありませんが、同一性を保持したいとか、オブジェクトがデカくてコピーするとパフォーマンスに影響が出るとか、宗教上の理由とかでコピーコンストラクタが勝手に呼ばれるのが好ましくない場合、躊躇することになります。

ハハハ、こんな時のために __block があるじゃないですか。
これで解決ですよ。

確かめてみると、元関数のcppObjとブロック内のcppObj、ちゃんと同じインスタンスになってます。

これで万事解決。。。。   と思いきや。。。

なんとここでしれっとコピーコンストラクタが呼ばれるではありませんか。
試しに CPPClass のコピーコンストラクタをprivateにするとこの文でエラーがでます。
なんと、一旦コピーと取った後に、元関数部分とブロック内部の両方でそのコピーを指すようになるっぽいですね。。。

えー。。。。 コピーが起きない方法はないものじゃろうか。。。

じゃあローカル変数じゃなくてnewでヒープに割り付ければいいじゃん。

ってなるのですが、newしたC++クラスはどこで delete するかが問題になります。

キャプチャ時に自動的にretain/releaseされるObjective-Cインスタンスとは違って、C++インスタンスの生ポインタにはそんな便利なことなんてしてくれません。
元の部分とブロックの内部のどちらか最後に不要になった方でプログラマの責任で確実に一度だけdeleteする必要があります

じゃあどうするか。

C++インスタンスもObjective-Cのように参照カウンタ形式で管理すれば良いのです。

幸い、C++11で参照カウンタで管理できる std::shared_ptr<>クラスが使えるようになりました。
早速使ってみよう。

オブジェクトの開放はshared_ptr任せでよく、deleteを書く必要はない。楽チン。
えっ ってカンジだけどこれで全部解決。

cppObjSPtr を構築した時点で参照カウンタは1。
ブロックにキャプチャされる時に cppObjSPtr が複製され、この時中のオブジェクトに対する参照カウンタが+1され、2になる。
後は、元の関数終了部分とブロック終了部分で、それぞれのcppObjSPtrが破棄され、中のオブジェクトに対する参照カウンタが−1される。
どっちが後になっても、後になった方で参照カウンタが0になり、その時に中のオブジェクトもdelete。
(実際にはキャプチャされた時とdispatch_asyncでブロックがコピーされた時で2回コピーが起きるのでもうちょっと動きがあるけど、にゅあんすでー)

dispatch_async越しに渡せるし、とてもARCっぽい。素晴らしい!!

cppObjSPtrはブロックにキャプチャされる際にコピーされるけど、指すオブジェクトは同じです。コピーが発生しない。万歳!

C++11によって、こういった微妙〜〜〜に困る問題が結構解決する。
C++11ばんじゃーい∩( ・ω・)∩