テラシュールブログ

旧テラシュールウェアブログUnity記事。主にUnityのTipsやAR・VR、ニコニコ動画についてのメモを残します。

object.ReferenceEquals(someObject, null) の方が someObject == null より早い…が、盲目的に使うのは危険

先日#UnityTipsにて、中々に面白いTipsが紹介されました。

 #UnityTipsとは

火曜日の大体夕方から夜にかけて、#UnityTipsのタグを付けてTipsを自慢する奴です。

 object.ReferenceEquals(someObject, null) の方が someObject == null より早い?

早速試してみたところ、中々に興味深い結果が出ました。

下の図は、上のコードを64bitPC向けにビルドしたアプリ上で10000000回実行した結果です。

f:id:tsubaki_t1:20150528005806p:plain

興味深いことに大体一桁近い違いが出ています。

ただ、この規模で実行してこの程度しか変化がないので、正直書き換える必要があるかと言われると微妙な気がします。

毎フレームnullチェック入れたり数万回nullチェックするのは、そもそも設計が間違っている気がしますし。

何故そんな事が起こるのか

これについては以下の記事で紹介しています。

blogs.unity3d.com

要するに「Unityのオブジェクトは実はC++で管理されており、C#はアクセス用ポインタのみを持つので、DestoryでC++のオブジェクトを削除してもC#的にはnullと判定されない」という所が問題になるみたいです。なので「== オペレーターを拡張して両方チェックするようにした」との事。これが単に参照のみをチェックするReferenceEqqualとの違いみたいです。

例えばオブジェクトをDestroyしたオブジェクトの確認を行う場合、 == オペレータではnullと判断してくれますがobject.ReferenceEquals(someObject, null) では null と判定されません

つまり?

個人的に紹介しといて何ですがこれは
事故のもとな気がします

 

安全に運用するには、Destroyしたオブジェクトは自分でちゃんとnullで埋めるDestroyされる可能性のあるシングルトンには使わない、使用はエディタを使いシーン上で設定するオブジェクトへの参照に限定する、…といった事が必要かなと。

 

パフォーマンスって言葉は魔法みたいですが、実際はほんとうに怖い

ちなみに

オブジェクト、Destroy直後はnullになりません。同一フレームでnullにしたければDestroyImmediateを使用します。

qiita.com

またカスタム演算子が??に使えないので、??はC#的な判定(つまりDestroy後nullにならない)が発生します。