オブジェクト演算子 (^) へのハンドル (C++/CLI および C++/CX)Handle to Object Operator (^) (C++/CLI and C++/CX)

ハンドル宣言子 (^、"ハット" と読みます) は、指定子の型を変更します。この指定子の型は、宣言されたオブジェクトがアクセス不能になったとシステムが判断すると、そのオブジェクトが自動的に削除されることを意味します。The handle declarator (^, pronounced "hat"), modifies the type specifier to mean that the declared object should be automatically deleted when the system determines that the object is no longer accessible.

宣言されたオブジェクトへのアクセスAccessing the Declared Object

ハンドル宣言子を指定して宣言した変数は、オブジェクトへのポインターのように動作します。A variable that is declared with the handle declarator behaves like a pointer to the object. ただし、変数はオブジェクト全体を指し示します。オブジェクトのメンバーを指すことはできません。また、ポインター演算をサポートしません。However, the variable points to the entire object, cannot point to a member of the object, and it does not support pointer arithmetic. オブジェクトにアクセスするには間接演算子 (*) を使用し、オブジェクトのメンバーにアクセスするには矢印のメンバー アクセス演算子 (->) を使用します。Use the indirection operator (*) to access the object, and the arrow member-access operator (->) to access a member of the object.

Windows ランタイムWindows Runtime

コンパイラは、COM 参照カウント メカニズムを使用して、オブジェクトがもう使用されず、削除してよいかどうかを判断します。The compiler uses the COM reference counting mechanism to determine if the object is no longer being used and can be deleted. これが可能なのは、Windows ランタイム インターフェイスから派生するオブジェクトが実際に COM オブジェクトであるためです。This is possible because an object that is derived from a Windows Runtime interface is actually a COM object. 参照カウントは、オブジェクトが作成されるかコピーされるとインクリメントされ、オブジェクトが null に設定されるかスコープから外れるとデクリメントされます。The reference count is incremented when the object is created or copied, and decremented when the object is set to null or goes out of scope. 参照カウントがゼロになると、オブジェクトは直ちに自動的に削除されます。If the reference count goes to zero, the object is automatically and immediately deleted.

ハンドル宣言子の利点は、煩雑でエラーが発生しやすいプロセスであるオブジェクトについて、COM では参照カウントを明示的に管理する必要があるということです。The advantage of the handle declarator is that in COM you must explicitly manage the reference count for an object, which is a tedious and error prone process. つまり、参照カウントをインクリメントおよびデクリメントするには、オブジェクトの AddRef() メソッドと Release() メソッドを呼び出す必要があります。That is, to increment and decrement the reference count you must call the object's AddRef() and Release() methods. ただし、ハンドル宣言子を使用してオブジェクトを宣言する場合、コンパイラでは、参照カウントを自動的に調整するコードを生成します。However, if you declare an object with the handle declarator, the compiler generates code that automatically adjusts the reference count.

オブジェクトをインスタンス化する方法の詳細については、「ref new」を参照してください。For information on how to instantiate an object, see ref new.

要件Requirements

コンパイラ オプション: /ZWCompiler option: /ZW

共通言語ランタイムCommon Language Runtime

システムは、CLR ガベージ コレクター メカニズムを使用して、オブジェクトがもう使用されず、削除してよいかどうかを判断します。The system uses the CLR garbage collector mechanism to determine if the object is no longer being used and can be deleted. 共通言語ランタイムが、オブジェクトを割り当てるヒープを保持し、プログラムでマネージド参照 (変数) を使用します。それによりヒープ内のオブジェクトの場所が示されます。The common language runtime maintains a heap on which it allocates objects, and uses managed references (variables) in your program indicate the location of objects on the heap. オブジェクトがもう使用されなくなると、オブジェクトがヒープで占有していたメモリが解放されます。When an object is no longer used, the memory that it occupied on the heap is freed. ガベージ コレクターは、解放済みメモリの使用を改善するために、定期的にヒープを圧縮します。Periodically, the garbage collector compacts the heap to better use the freed memory. ヒープを圧縮すると、ヒープのオブジェクトを移動できます。これにより、マネージド参照によって参照される場所が無効になります。Compacting the heap can move objects on the heap, which invalidates the locations referred to by managed references. ただし、ガベージ コレクターは、すべてのマネージド参照の場所を認識しており、ヒープ内のオブジェクトの現在の場所を示すようにマネージド参照を自動的に更新します。However, the garbage collector is aware of the location of all managed references, and automatically updates them to indicate the current location of the objects on the heap.

ネイティブ C++ ポインター (*) と参照 (&) は、マネージド参照ではないため、それらが指し示すアドレスをガベージ コレクターは自動的に更新できません。Because native C++ pointers (*) and references (&) are not managed references, the garbage collector cannot automatically update the addresses they point to. この問題を解決するには、ガベージ コレクターが認識しており自動的に更新できる変数を、ハンドル宣言子を使用して指定します。To solve this problem, use the handle declarator to specify a variable that the garbage collector is aware of and can update automatically.

詳細については、「方法 :ネイティブ型のハンドルを宣言する」を参照してください。For more information, see How to: Declare Handles in Native Types.

使用例Examples

このサンプルは、マネージド ヒープ上で参照型のインスタンスを作成する方法を示しています。This sample shows how to create an instance of a reference type on the managed heap. また、このサンプルでは、1 つのハンドルを別のハンドルで初期化することができ、その結果、ガベージ コレクトされたマネージド ヒープ上で同じオブジェクトへの参照が 2 つ作成されることも示しています。This sample also shows that you can initialize one handle with another, resulting in two references to same object on managed, garbage-collected heap. 1 つのハンドルに nullptr を割り当てても、オブジェクトはガベージ コレクションの対象としてマークされないことに注意してください。Notice that assigning nullptr to one handle does not mark the object for garbage collection.

// mcppv2_handle.cpp
// compile with: /clr
ref class MyClass {
public:
   MyClass() : i(){}
   int i;
   void Test() {
      i++;
      System::Console::WriteLine(i);
   }
};

int main() {
   MyClass ^ p_MyClass = gcnew MyClass;
   p_MyClass->Test();

   MyClass ^ p_MyClass2;
   p_MyClass2 = p_MyClass;

   p_MyClass = nullptr;
   p_MyClass2->Test();
}
1
2

次の例では、マネージド ヒープ上のオブジェクト (オブジェクトの型はボックス化された値型) へのハンドルを宣言する方法を示しています。The following sample shows how to declare a handle to an object on the managed heap, where the type of object is a boxed value type. また、このサンプルでは、ボックス化されたオブジェクトから値型を取得する方法も示します。The sample also shows how to get the value type from the boxed object.

// mcppv2_handle_2.cpp
// compile with: /clr
using namespace System;

void Test(Object^ o) {
   Int32^ i = dynamic_cast<Int32^>(o);

   if(i)
      Console::WriteLine(i);
   else
      Console::WriteLine("Not a boxed int");
}

int main() {
   String^ str = "test";
   Test(str);

   int n = 100;
   Test(n);
}
Not a boxed int
100

この例では、任意のオブジェクトを指し示すvoid* ポインターを使用した C++ の共通の表現形式が、任意の参照クラスへのハンドルも保持できる Object^ で置き換えられることを示しています。This sample shows that the common C++ idiom of using a void* pointer to point to an arbitrary object is replaced by Object^, which can hold a handle to any reference class. また、配列やデリゲートなど、すべての型がオブジェクト ハンドルに変換できることも示しています。It also shows that all types, such as arrays and delegates, can be converted to an object handle.

// mcppv2_handle_3.cpp
// compile with: /clr
using namespace System;
using namespace System::Collections;
public delegate void MyDel();
ref class MyClass {
public:
   void Test() {}
};

void Test(Object ^ x) {
   Console::WriteLine("Type is {0}", x->GetType());
}

int main() {
   // handle to Object can hold any ref type
   Object ^ h_MyClass = gcnew MyClass;

   ArrayList ^ arr = gcnew ArrayList();
   arr->Add(gcnew MyClass);

   h_MyClass = dynamic_cast<MyClass ^>(arr[0]);
   Test(arr);

   Int32 ^ bi = 1;
   Test(bi);

   MyClass ^ h_MyClass2 = gcnew MyClass;

   MyDel^ DelInst = gcnew MyDel(h_MyClass2, &MyClass::Test);
   Test(DelInst);
}
Type is System.Collections.ArrayList

Type is System.Int32

Type is MyDel

このサンプルは、ハンドルが逆参照できること、および逆参照されるハンドル経由でメンバーにアクセスできることを示しています。This sample shows that a handle can be dereferenced and that a member can be accessed via a dereferenced handle.

// mcppv2_handle_4.cpp
// compile with: /clr
using namespace System;
value struct DataCollection {
private:
   int Size;
   array<String^>^ x;

public:
   DataCollection(int i) : Size(i) {
      x = gcnew array<String^>(Size);
      for (int i = 0 ; i < Size ; i++)
         x[i] = i.ToString();
   }

   void f(int Item) {
      if (Item >= Size)
      {
         System::Console::WriteLine("Cannot access array element {0}, size is {1}", Item, Size);
         return;
      }
      else
         System::Console::WriteLine("Array value: {0}", x[Item]);
   }
};

void f(DataCollection y, int Item) {
   y.f(Item);
}

int main() {
   DataCollection ^ a = gcnew DataCollection(10);
   f(*a, 7);   // dereference a handle, return handle's object
   (*a).f(11);   // access member via dereferenced handle
}
Array value: 7

Cannot access array element 11, size is 10

このサンプルでは、ネイティブ参照 (&) をマネージド型の int メンバーにバインドできないことを示しています。これは、ガベージ コレクトされたヒープに int が格納される可能性があり、またネイティブ参照がマネージド ヒープ上のオブジェクトの移動を追跡しないためです。This sample shows that a native reference (&) can’t bind to an int member of a managed type, as the int might be stored in the garbage collected heap, and native references don’t track object movement in the managed heap. 解決策は、ローカル変数を使用すること、または、&% に変更して、追跡参照にすることです。The fix is to use a local variable, or to change & to %, making it a tracking reference.

// mcppv2_handle_5.cpp
// compile with: /clr
ref struct A {
   void Test(unsigned int &){}
   void Test2(unsigned int %){}
   unsigned int i;
};

int main() {
   A a;
   a.i = 9;
   a.Test(a.i);   // C2664
   a.Test2(a.i);   // OK

   unsigned int j = 0;
   a.Test(j);   // OK
}

要件Requirements

コンパイラ オプション: /clrCompiler option: /clr

関連項目See also

.NET および UWP でのコンポーネント拡張Component Extensions for .NET and UWP
参照演算子の追跡Tracking Reference Operator