Copy 関数
一般的に、単純な代入とも呼ばれる標準的なコピー操作は、= 演算子を使用して、ある変数の値を別の変数に代入するときに発生します。たとえば、式 myInt2 = myInt1 は、myInt1 の整数の内容を、myInt1 が使用するメモリから myInt2 が使用するメモリにコピーします。コピー操作の後、2 つの別々のメモリ領域に同じ値が含まれます。ただし、このように Core Foundation オブジェクトをコピーしようとすると、オブジェクト自体を複製せず、オブジェクトへの 参照 だけを複製することに注意してください。
たとえば、Core Foundation を初めてお使いの方は、CFString オブジェクトのコピーを作成するには、式 myCFString2 = myCFString1 を使用する事を考えるかもしれません。ここでも、この式は実際には文字列データをコピーしません。myCFString1 と myCFString2 の両方とも CFStringRef 型を持たなければならないため、この式はオブジェクトへの参照のみをコピーします。コピー操作の後、CFString への参照の 2 つのコピーができます。このタイプのコピーは参照が重複しているだけのため非常に高速ですが、このように可変オブジェクトをコピーすることは危険だと知るのは重要です。グローバル変数を使用するプログラムと同様に、アプリケーションのある部分が参照のコピーを使用してオブジェクトを変更した場合、その参照のコピーを持つプログラムの他の部分がデータが変更されたことを知る方法はありません。
オブジェクトを複製しようとする場合は、この目的のために Core Foundation が提供する関数の 1 つを使用しなければなりません。CFString の例を続けると、CFStringCreateCopy を使用して元のデータと同じデータを含むまったく新しい CFString オブジェクトを作成します。"CreateCopy" 関数を持つ Core Foundation 型には、変更可能なオブジェクトのコピーを返すバリアント(変異) "CreateMutableCopy" も用意されています。
浅いコピー
複合オブジェクト、つまり他のオブジェクトを含むことができるコレクションオブジェクトなどのコピーも注意して行わなければなりません。予想通り、= 演算子を使用してこれらのオブジェクトでコピーを実行すると、オブジェクト参照が複製されます。CFString や CFData のような単純なオブジェクトとは対照的に、CFArray や CFSet などの複合オブジェクトに提供される "CreateCopy" 関数は、実際には 浅いコピー を実行します。これらのオブジェクトの場合、浅いコピーとは、新しいコレクションオブジェクトが作成されますが、元のコレクションの内容は複製されないことを意味します。オブジェクト参照のみが新しいコンテナにコピーされます。このタイプのコピーは、たとえば、配列が不変で、並べ替えたい場合などに便利です。この場合、含まれているオブジェクトをすべて複製する必要はありません。なぜなら、オブジェクトを変更する必要がないからです。その余分なメモリを使い切るのはなぜですか?あなたは、含まれているオブジェクトのセットを変更したいだけです。単純なタイプのオブジェクト参照をコピーする場合と同じリスクが適用されます。
深いコピー
まったく新しい複合オブジェクトを作成したい場合は、深いコピー を実行しなければなりません。深いコピーは、複合オブジェクトとそれに含まれるすべてのオブジェクトの内容を複製します。Core Foundation の現在のリリースには、プロパティリストの深いコピーを実行する関数が含まれています (CFPropertyListCreateDeepCopy を参照の事)。他の構造体の深いコピーを作成したい場合は、複合オブジェクトに再帰的に降りてその内容全体を 1 つずつコピーすることで、深いコピーを自分で実行することができます。複合オブジェクトは再帰的に実行できるので、この機能を実装する際には注意してください。再帰的ループを引き起こす可能性のある、それら自身への参照を直接的または間接的に含む場合があります。
前の章 次の章