Operator uchwytu do obiektu (^) (C++/CLI i C++/CX)

Deklarator uchwytu (^wymawiany "hat"), modyfikuje specyfikator typu, aby oznaczał, że zadeklarowany obiekt powinien zostać automatycznie usunięty, gdy system ustali, że obiekt nie jest już dostępny.

Uzyskiwanie dostępu do zadeklarowanej obiektu

Zmienna zadeklarowana za pomocą deklaratora dojścia zachowuje się jak wskaźnik do obiektu. Jednak zmienna wskazuje cały obiekt, nie może wskazać elementu członkowskiego obiektu i nie obsługuje arytmetyki wskaźnika. Użyj operatora pośredniego (*), aby uzyskać dostęp do obiektu, oraz operatora dostępu do elementu członkowskiego strzałki (->), aby uzyskać dostęp do elementu członkowskiego obiektu.

Środowisko wykonawcze systemu Windows

Kompilator używa mechanizmu zliczania odwołań COM, aby określić, czy obiekt nie jest już używany i można go usunąć. Jest to możliwe, ponieważ obiekt pochodzący z interfejsu środowisko wykonawcze systemu Windows jest w rzeczywistości obiektem COM. Liczba odwołań jest zwiększana, gdy obiekt jest tworzony lub kopiowany, i dekrementowany, gdy obiekt jest ustawiony na wartość null lub wykracza poza zakres. Jeśli liczba odwołań przekroczy zero, obiekt zostanie automatycznie i natychmiast usunięty.

Zaletą deklaratora obsługi jest to, że w modelu COM należy jawnie zarządzać liczbą odwołań dla obiektu, który jest żmudny i podatny na błędy. Oznacza to, że aby zwiększyć i zdekrementować liczbę odwołań, należy wywołać metody AddRef() i Release() obiektu. Jeśli jednak zadeklarujesz obiekt za pomocą deklaratora dojścia, kompilator generuje kod, który automatycznie dostosowuje liczbę odwołań.

Aby uzyskać informacje na temat tworzenia wystąpień obiektu, zobacz ref new (Ref new).

Wymagania

Opcja kompilatora: /ZW

środowiska uruchomieniowe w trakcie wykonania

System używa mechanizmu modułu odśmiecacz pamięci CLR, aby określić, czy obiekt nie jest już używany i można go usunąć. Środowisko uruchomieniowe języka wspólnego utrzymuje stertę, na której przydziela obiekty, i używa zarządzanych odwołań (zmiennych) w programie wskazuje lokalizację obiektów na stercie. Gdy obiekt nie jest już używany, pamięć zajmowana na stercie jest zwalniana. Okresowo moduł odśmiecania pamięci kompakuje stertę, aby lepiej korzystać z zwolnionej pamięci. Kompaktowanie sterty może przenosić obiekty na stercie, co unieważnia lokalizacje, do których odwołują się odwołania zarządzane. Jednak moduł odśmieceń pamięci jest świadomy lokalizacji wszystkich zarządzanych odwołań i automatycznie aktualizuje je, aby wskazać bieżącą lokalizację obiektów na stercie.

Ponieważ natywne wskaźniki języka C++ () i odwołania (*&) nie są odwołaniami zarządzanymi, moduł odśmiecanie pamięci nie może automatycznie aktualizować adresów, do których wskazują. Aby rozwiązać ten problem, należy użyć deklaratora do obsługi, aby określić zmienną, o którą pamięta moduł odśmiecenia pamięci i może aktualizować automatycznie.

Aby uzyskać więcej informacji, zobacz Instrukcje: deklarowanie dojść w typach natywnych.

Przykłady

W tym przykładzie pokazano, jak utworzyć wystąpienie typu odwołania na zarządzanym stercie. W tym przykładzie pokazano również, że można zainicjować jeden uchwyt z innym, co powoduje dwa odwołania do tego samego obiektu na zarządzanym, zbieranym odśmieszceniu pamięci. Zwróć uwagę, że przypisanie wartości nullptr do jednego dojścia nie oznacza obiektu do odzyskiwania pamięci.

// 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

W poniższym przykładzie pokazano, jak zadeklarować uchwyt do obiektu na zarządzanym stercie, gdzie typ obiektu jest typem wartości pola. W przykładzie pokazano również, jak uzyskać typ wartości z obiektu pola.

// 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

W tym przykładzie pokazano, że typowy idiom języka C++ przy użyciu void* wskaźnika wskazującego na dowolny obiekt jest zastępowany przez Object^element , który może pomieścić uchwyt do dowolnej klasy referencyjnej. Pokazuje również, że wszystkie typy, takie jak tablice i delegaty, można przekonwertować na uchwyt obiektu.

// 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

W tym przykładzie pokazano, że dojście może zostać wyłuszczone i że można uzyskać dostęp do elementu członkowskiego za pośrednictwem uchwytu wyłuszczonego.

// 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

W tym przykładzie pokazano, że odwołanie natywne (&) nie może wiązać się z elementem int członkowskim typu zarządzanego, ponieważ int może być przechowywane w stercie zbieranym przez śmieci, a odwołania natywne nie śledzą ruchu obiektów w zarządzanym stercie. Poprawka polega na użyciu zmiennej lokalnej lub zmiany & na %, co spowoduje odwołanie do śledzenia.

// 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
}

Wymagania

Opcja kompilatora: /clr

Zobacz też

Rozszerzenia składników dla platformy .NET i platformy uniwersalnej systemu Windows
Operator odwołania śledzenia