Operátor popisovače objektu (^) (C++/CLI a C++/CX)
Deklarátor popisovače (^
vyslovovaný "hat"), upraví specifikátor typu tak, aby měl být deklarovaný objekt automaticky odstraněn, když systém zjistí, že objekt již není přístupný.
Přístup k deklarovanému objektu
Proměnná deklarovaná pomocí deklarátoru popisovače se chová jako ukazatel na objekt. Proměnná však odkazuje na celý objekt, nemůže odkazovat na člena objektu a nepodporuje aritmetické ukazatele. Pro přístup k objektu použijte operátor nepřímého přístupu (*
) a operátor pro přístup člena šipky (->
) pro přístup k členu objektu.
prostředí Windows Runtime
Kompilátor používá mechanismus počítání odkazů modelu COM k určení, zda objekt již není používán a lze jej odstranit. To je možné, protože objekt odvozený z rozhraní prostředí Windows Runtime je ve skutečnosti objekt COM. Počet odkazů se zvýší při vytvoření nebo zkopírování objektu a dekrementuje se, když je objekt nastaven na hodnotu null nebo přestane být obor. Pokud počet odkazů přejde na nulu, objekt se automaticky a okamžitě odstraní.
Výhodou deklarátoru popisovače je, že v modelu COM musíte explicitně spravovat počet odkazů pro objekt, což je zdlouhavý a náchylný proces chyby. To znamená, že chcete-li zvýšit a zvýšit počet odkazů, musíte volat metody AddRef() a Release() objektu. Pokud však deklarujete objekt s deklarátorem popisovače, kompilátor vygeneruje kód, který automaticky upraví počet odkazů.
Informace o tom, jak vytvořit instanci objektu, naleznete v tématu odkaz nové.
Požadavky
Možnost kompilátoru: /ZW
CLR (Common Language Runtime)
Systém používá mechanismus uvolňování paměti CLR k určení, jestli se objekt už nepoužívá a lze jej odstranit. Modul CLR (Common Language Runtime) udržuje haldu, na které přiděluje objekty, a používá spravované odkazy (proměnné) ve vašem programu označující umístění objektů v haldě. Pokud se objekt už nepoužívá, uvolní se paměť, kterou zabírá na haldě. Uvolňování paměti pravidelně komprimuje haldu, aby lépe používala uvolněnou paměť. Komprimace haldy může přesunout objekty v haldě, která zneplatní umístění odkazované spravovanými odkazy. Systém uvolňování paměti však ví o umístění všech spravovaných odkazů a automaticky je aktualizuje tak, aby označoval aktuální umístění objektů v haldě.
Vzhledem k tomu, že nativní ukazatele jazyka C++ a odkazy (*
&
) nejsou spravované odkazy, systém uvolňování paměti nemůže automaticky aktualizovat adresy, na které odkazují. Chcete-li tento problém vyřešit, pomocí deklarátoru popisovače určete proměnnou, o které je systém uvolňování paměti informován a může se automaticky aktualizovat.
Další informace naleznete v tématu Postupy: Deklarace popisovačů v nativních typech.
Příklady
Tato ukázka ukazuje, jak vytvořit instanci referenčního typu ve spravované haldě. Tato ukázka také ukazuje, že můžete inicializovat jeden popisovač s druhým, což vede ke dvěma odkazům na stejný objekt při spravované haldě shromážděné paměti. Všimněte si, že přiřazení nullptr k jednomu popisovači neoznačuje objekt pro uvolňování paměti.
// 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
Následující ukázka ukazuje, jak deklarovat popisovač objektu ve spravované haldě, kde typ objektu je typ hodnoty v rámečku. Ukázka také ukazuje, jak získat typ hodnoty z boxovaného objektu.
// 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
Tato ukázka ukazuje, že společný idiom jazyka C++ použití void*
ukazatele na odkaz na libovolný objekt je nahrazen , Object^
který může obsahovat popisovač jakékoli referenční třídy. Ukazuje také, že všechny typy, jako jsou pole a delegáti, lze převést na popisovač objektu.
// 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
Tato ukázka ukazuje, že popisovač může být dereferenced a že člen může být přístupný prostřednictvím popisovače dereferenced.
// 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
Tato ukázka ukazuje, že nativní odkaz (&
) nemůže svázat s int
členem spravovaného typu, protože int
může být uložen v haldě s uvolňováním paměti a nativní odkazy nesledují přesun objektů ve spravované haldě. Opravou je použití místní proměnné nebo změna &
, aby se odkaz na %
sledování použil.
// 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
}
Požadavky
Možnost kompilátoru: /clr
Viz také
Přípony komponent pro .NET a UPW
Operátor sledovacího odkazu