对象句柄运算符 (^)(C++ 组件扩展)
处理声明 (^,清单 “帽子”),修改该类型 说明符 表示应自动删除声明的对象,当系统认为对象不能再行访问。
访问声明的对象
声明了处理声明的变量的行为类似于指针为对象。 但是,变量指向整个对象,不能指向对象的成员,则,因此不支持指针算法。 使用间接寻址运算符 (*) 访问对象和箭头成员访问运算符 (->) 访问对象的成员。
Windows 运行时
编译器使用 COM 引用计数 framework 确定是否不再使用对象并且可能会被删除。 之所以可以这样,是因为从窗口运行时接口派生的对象实际上是 COM 对象。 引用计数递增,在创建对象时或复制,而递减对象时,设置为 null 时或超出范围。 如果引用计数为零,对象会自动和立即删除。
处理声明的优点在于当您必须显式管理对象的引用计数,单调乏味的,且容易出错进程的 COM。 即递增和递减引用计数必须调用对象的 AddRef () 和释放 () 方法。 但是,因此,如果声明句柄声明的对象, Visual C++ 编译器生成自动调整引用计数的代码。
有关如何实例化对象的信息,请参见 新的所有输出。
要求
编译器选项: /ZW
公共语言运行时
系统将使用 CLR 垃圾回收器 framework 确定是否不再使用对象并且可能会被删除。 公共语言运行时维护其分配对象堆,因此,使用托管程序中的引用 (变量) 指示对象的位置堆中的。 当不再使用对象时,它在堆占用的内存被释放。 循环,垃圾回收器压缩堆改进使用已释放的内存。 压缩堆中移动堆中的对象, void 管理引用的位置引用。 但是,垃圾回收器了解位置所有托管引用并自动更新它们指示对象的当前位置堆中的。
由于其指向的本机 C++ 指针 (*) 和引用 (&) 未托管引用,垃圾回收器就不能自动更新地址。 若要解决此问题,请使用处理声明指定变量垃圾回收器了解且会自动更新。
在 Visual C++ 2002 和 Visual C++ 2003, __gc * 用于声明在托管堆上的对象。 ^ 替换在新语法中 __gc * 。
有关更多信息,请参见 如何:使用本机类型声明句柄。
示例
示例
本示例演示如何创建一个引用类型的实例在托管堆中。 此示例还演示,可以初始化具有另一个的句柄,导致两对托管,垃圾回收堆的相同的对象。 通知分配 nullptr(C++ 组件扩展) 到句柄不指示垃圾回收的对象。
// 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();
}
Output
示例
下面的示例演示如何声明处理到托管堆上的对象,对象的类型是一个装箱值类型。 该示例还演示如何从获取装箱的对象的值类型。
// 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);
}
Output
示例
此示例演示,使用 void* 指针常见 C++ 个指向任意对象。 System::object^ 替换,它可以保存句柄的任何引用类。 它还演示,所有类型,如数组和委托,可以转换为对象处理。
// 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);
}
Output
示例
此示例演示处理可以被取消引用,因此,成员可以通过一个取消对句柄进行访问。
// 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
}
Output
示例
此示例演示,本机引用 (&) 不能绑定到 int 托管类型的成员, int ,在垃圾回收堆中存储,因此,本机引用不跟踪在托管堆上的对象移动。 这种解决方法是使用局部变量,或者更改 & 到 %,使其成为跟踪引用。
// 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
}
要求
编译器选项: /clr