C++/CLI中的Handle和Reference小記
最近看了看C++/CLI specification。 的確,C++/CLI讓C++在使用.NET的時候手感好了很多,一點學習小記,說的不對,各位多包涵。
Handle Type
對于CLI中的任意一個類型T,T^聲明了一個T的handle類型,它用來指向創建在CLI Heap上的對象。由于創建載托管堆上的對象的位置有可能被運行時改變,因此,一個Handle類型可以動態跟蹤其指向的對象。從某種意義上說,我們可以把Handle類型看作是托管堆上的指針,而把native pointer看作是原生堆上的指針。
一個handle類型變量的默認值是nullptr。
通過gcnew關鍵字,你可以在托管堆上創建一個CLI對象,這樣的對象只能夠通過handle來訪問。例如:
R^ r1 = gcnew R; // Allocate an Object on the CLI heap
R^ r2 = r1;?? // Handles r1 and r2 refer to the same object
除非使用delete或者顯式調用一個CLI對象的析構函數,否則CLI對象的析構函數絕對不會被調用。但是,當程序結束的時候,GC會回收對象的內存,并且如果一個對象有finalizer,這個東西倒是會被調用。例如:
ref
class T {
public
:
??? T() { }
??? ~T() {
??????? System::Console::WriteLine("I'm destructor!"); }
??? !T() {
??????? System::Console::WriteLine("I'm finalizer!");
??? }
};
之后:
{
??????? T^ t1 = gcnew T();
}
會看到只有finalizer被調用了,而:
{
???????
delete t;
}
會看到析構函數被調用了。也就是說,對于一個托管對象,有2種清理方式。一種是通過析構函數進行確定性的清除;另一種是讓CLI調用類對象的finalizer。
l
????????
和原生指針不同,handle類型的變量具有跟蹤功能,也就是說一個handle類型的變量可以根據其指向的CLI heap中對象的位置而改變(因為GC可能會移動托管堆中的對象)。也就是說:handle類型不能轉換成void*,也不能進行相反的轉換
l
????????
handle
類型不能轉換成整數類型,也不能進行相反的轉換
l
????????
不能對handle類型進行排序
l
????????
Handle
類型的變量只能指向CLI heap中的對象
例如:
R^ r4 = new R;?
Object^ o = r4;// OK
R^ r5 = dynamic_cast
long
l = reinterpret_cast<long>(r5); //error, can't convert to integer
R^ r6 = reinterpret_cast
std::set
所有指向同一個托管對象的引用都可以被看作是等價的,即使對象被GC移動了也是如此。一個handle可以有任意的生存周期。也可以被指定成nullptr。對于一個handle類型的變量,你也可以通過*來或得其指向的對象的引用。
Reference Type
一個原生引用可以被邦定到任何做為左值的原生變量(lvalue)上。
作為一個托管堆中的對象,由于GC有可能移動它的位置,因此它的位置必須被跟蹤。因此,對于這樣的對象的引用被稱為tracking reference(%),由于存在gc-lvalue和lvalue的隱式轉換,所以一個track reference可以既可以邦定到gc-lvalue,也可以邦定到lvalue。當其邦定到一個lvalue時,取其地址獲得的是一個原生指針,否則獲得的就是一個托管handle。例如:
R^ h = gcnew R; // allocate on CLI heap
R& r = *h;??? ? // bind tracking reference to ref class obj
void
F(V% r);
F(*gcnew V);? // bind tracking reference to value class obj
N* p = new N();
N% rn = *p; ???// bind to native object;
和一個普通的引用一樣,一個tracking reference也是不可以重邦定的。一旦在聲明時被指定了對象,就不可以再進行更改。另外你也只可以把tracking reference類型的變量定義成automatic型的。
如果一個tracking reference被邦定到某個值類型的基類,那么這個tracking reference便不能邦定到這個派生的值類型。也就是說一個System::Object%不可以邦定到一個System::ValueType對象上。