2012-01-18 2 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. Также верно ли, что типы значений должны использовать семантику стека, чтобы сделать код эффективным? i.e вместо 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

Это * другой * вопрос, не стесняйтесь спрашивать его в новом вопросе. –

2

Что касается вашего второго вопроса: Да, вы должны удалить ^, когда используете типы значений в C++/CLI. Я не знаю, что есть большая эффективность, но это стандарт для типов значений.

ValBase valBase1; является C++/CLI, эквивалентным C# -коду ValBase valBase1 = new ValBase();. Не существует эквивалента C# для кода C++/CLI ValBase^ valBase1. Если вы используете для типов значений, вы обнаружите, что у вас возникли проблемы с вызовом .NET API, так как ValBase^ и ValBase - это разные типы.

Если вам нужно вызвать конструктор не по умолчанию для типа значения, вот синтаксис. Поскольку нет распределения кучи (управляемого или неуправляемого), нет new или gcnew, просто вызовите конструктор напрямую.

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

Вы также можете удалить ^ на ссылочных типов, и что будет скомпилирован в примерочных, наконец-отчуждать блок. Пример:

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(); 
} 
Смежные вопросы