2012-01-18 116 views
0
value class ValBase 
{ 
    public: 
    int a; 
}; 

ref class RefBase 
{ 
public: 
    int a; 
}; 

int main(array<System::String ^> ^args) 
{ 

RefBase^ RefBase1 = gcnew RefBase; //LEGAL. Ref type Managed Obj created on CLR heap. 
ValBase^ ValBase1 = gcnew ValBase; //LEGAL. Value type Managed Obj created on CLR heap. 

RefBase* RefBase2 = new RefBase; //ILLEGAL: new cannot be used on Managed Ref Class 
ValBase* ValBase2 = new ValBase; //This compiles okay but where is this "Managed Object" stored ? CLR heap or Native heap ? 

} 

在上次分配中,託管對象存儲在哪裏?我對C++ CLI完全陌生。另外,值類型是否應該使用堆棧語義來提高代碼的效率?即代替ValBase ValBase1 = gcnew ValBase,我應該使用ValBase ValBase1;此管理對象在哪裏存儲?

回答

1

只需添加一個引用類型的值類型的成員:

value class ValBase 
{ 
    public: 
     String^ s; 
     int a; 
}; 

... 
ValBase* = new ValBase; 

,編譯器會告訴你究竟在何處存儲:

錯誤C3255:' ValBase':不能在本地堆上動態分配此值類型對象

語義很簡單,畢竟你可以在棧上存儲一個值類型。如果它可以放在堆棧上,那麼它也可以放在本地堆上。只要它不包含垃圾回收器需要找回的對象。這就是C3255在那裏的原因。出於這個原因,.NET框架中存在值類型,將東西存儲在堆棧上很便宜並且使代碼效率更高。

但是,僅僅因爲它是可能將其存儲在本機堆沒有使它正好有用這樣做。對於ValBase^ ValBase1 = gcnew ValBase;也是如此,它在託管堆上存儲盒裝值。嵌入在System :: Object中的值的副本。拳擊是非常有用的,因爲它允許假裝值從Object繼承。但它並不便宜,絕不是因爲沒有理由而想要做的事情。

+0

這是另一個問題,請不要猶豫,在新的問題中提出。 – 2012-01-19 21:34:05

2

至於你的第二個問題:是的,當你在C++/CLI中使用值類型時,你應該刪除^。我不知道效率提高很多,但這是價值類型的標準。

ValBase valBase1;是與C#代碼相同的C++/CLI代碼ValBase valBase1 = new ValBase();。沒有C#等價於C++/CLI代碼ValBase^ valBase1。如果在值類型上使用^,則會發現調用.NET API時存在問題,因爲ValBase^ValBase是不同的類型。

如果您需要在值類型上調用非默認構造函數,請使用以下語法。由於沒有堆分配(託管或非託管),因此沒有newgcnew,只需直接調用構造函數即可。

ValueTypeFoo foo = ValueTypeFoo("bar", "baz"); 

您還可以在引用類型刪除^,這將編譯成一個try-finally-處置塊。例如:

StringBuilder sb; 
sb.Append("foo"); 
return sb.ToString(); 

// Equivalent to: 

StringBuilder^ sb = nullptr; 
try 
{ 
    sb = gcnew StringBuilder(); 
    sb->Append("foo"); 
    return sb->ToString(); 
} 
finally 
{ 
    IDisposable^ disp = dynamic_cast<IDisposable^>(sb); 
    if(disp != nullptr) disp->Dispose(); 
}