Отслеживание ссылок в C ++ / CLI - PullRequest
7 голосов
/ 01 августа 2010

Может кто-нибудь объяснить мне следующий фрагмент кода?

value struct ValueStruct {
    int x;
};

void SetValueOne(ValueStruct% ref) {
    ref.x = 1;
}

void SetValueTwo(ValueStruct ref) {
    ref.x = 2;
}

void SetValueThree(ValueStruct^ ref) {
    ref->x = 3;
}

ValueStruct^ first = gcnew ValueStruct;
first->x = 0;
SetValueOne(*first);

ValueStruct second;
second.x = 0;
SetValueTwo(second); // am I creating a copy or what? is this copy Disposable even though value types don't have destructors?

ValueStruct^ third = gcnew ValueStruct;
third->x = 0;
SetValueThree(third); // same as the first ?

И мой второй вопрос: есть ли причина иметь что-то подобное?:

ref struct RefStruct {
    int x;
};

RefStruct% ref = *gcnew RefStruct;
// rather than:
// RefStruct^ ref = gcnew RefStruct;

// can I retrieve my handle from ref?
// RefStruct^ myref = ???

Более того: я не вижу разницы между типом значения и типом ref, поскольку оба могут указывать обработчиком; (

1 Ответ

24 голосов
/ 01 августа 2010

Помните, что основное использование C ++ / CLI для разработки библиотек классов для использования графическими интерфейсами / веб-сервисами, созданными на других языках .NET.Поэтому C ++ / CLI должен поддерживать как ссылочный, так и тип значений, потому что другие языки .NET поддерживают.

Кроме того, C # может иметь также ref параметры, которые также являются типизированными значениями, это не уникально для C ++ / CLIи это никоим образом не делает типы значений эквивалентными ссылочным типам.

Чтобы ответить на вопросы в комментариях к коду:

я создаю копию или что?

Да, SetValueTwo принимает свой параметр по значению, поэтому создается копия.

Является ли эта копия доступной, даже если у типов значений нет деструкторов?

Неверно.Типы значений могут иметь деструкторы.Типы значений не могут иметь финализаторы.Поскольку этот конкретный тип значения имеет тривиальный деструктор, компилятор C ++ / CLI не заставит его реализовать IDisposable.В любом случае, если параметр является типом значения IDisposable, компилятор C ++ / CLI будет гарантировать, что Dispose вызывается, когда переменная выходит из области видимости, как семантика стека для локальных переменных.Это включает ненормальное завершение (выброшенное исключение) и позволяет использовать управляемые типы с RAII.

Оба

ValueStruct% ref = *gcnew ValueStruct;

и

ValueStruct^ ref = gcnew ValueStruct;

разрешены и помещеныэкземпляр типа значения в штучной упаковке в управляемой куче (которая вовсе не куча, а очередь FIFO, однако Microsoft предпочитает называть ее кучей, подобной области собственной памяти для динамического выделения).

В отличие от C #, C ++ / CLI может хранить типизированные дескрипторы в упакованных объектах.

Если ссылка отслеживания относится к экземпляру типа значения в стеке или встроена в другой объект, то содержимое типа значения должно быть упаковано в процессесформировал ссылку.

Отслеживание ссылок также можно использовать с ссылочными типами, и синтаксис для получения дескриптора такой же:

RefClass^ newinst = gcnew RefClass();
RefClass% reftoinst = *newinst;
RefClass^% reftohandle = newinst;

RefClass stacksem;
RefClass^ ssh = %stacksem;

Одна вещь, которую я никогда не смогу вспомнить полностьюзаключается в том, что синтаксис не на 100% согласован по сравнению с собственным C ++.

Объявление ссылки:

int& ri = i; // native
DateTime% dtr = dt; // managed tracking reference

Объявление указателя:

int* pi; // native
Stream^ sh; // tracking handle

Формирование указателя:

int* pi = &ri; // address-of native object
DateTime^ dth = %dtr; // address-of managed object

Обратите внимание, что унарный оператор адреса совпадает с эталонной нотацией как в стандартном C ++, так и в C ++ / CLI.Похоже, это противоречит ссылка отслеживания не может быть использована в качестве унарного оператора получения адреса (MSDN) , к которому я вернусь через секунду.

Во-первых, несоответствие:

Сформируйте ссылку из указателя:

int& iref = *pi;
DateTime% dtref = *dth;

Обратите внимание, что унарный оператор разыменования всегда *.Это то же самое, что указатель указателя только в родном мире, который полностью противоположен адресу, который, как упоминалось выше, всегда совпадает с обозначением ссылки.

Скомпилируемый пример:

DateTime^ dth = gcnew DateTime();
DateTime% dtr = *dth;

DateTime dt = DateTime::Now;
DateTime^ dtbox = %dt;

FileInfo fi("temp.txt");
// FileInfo^ fih = &fi;  causes error C3072
FileInfo^ fih = %fi;

Теперь об унарном адресе:

Во-первых, статья MSDN неверна, когда говорится:

В следующем примере показано, что ссылка на отслеживание не может бытьиспользуется в качестве унарного оператора получения адреса.

Правильное утверждение:

% - оператор адреса для создания дескриптора отслеживания.Однако его использование ограничено следующим образом:

Дескриптор отслеживания должен указывать на объект в управляемой куче.Справочные типы всегда существуют в управляемой куче, поэтому проблем нет.Однако типы значений и собственные типы могут находиться в стеке (для локальных переменных) или могут быть встроены в другой объект (переменные-члены типа значения).Попытки сформировать дескриптор отслеживания сформируют дескриптор в коробочной копии переменной: дескриптор не связан с исходной переменной.В результате процесса упаковки, который требует метаданных, которые не существуют для собственных типов, никогда не будет возможности иметь дескриптор отслеживания для экземпляра собственного типа.

Пример кода:

int i = 5;
// int^ ih = %i;  causes error C3071

System::Int32 si = 5;
// System::Int32^ sih = %si; causes error C3071
// error C3071: operator '%' can only be applied to an instance 
//              of a ref class or a value-type

Если System::Int32 не тип значения, тогда я не знаю, что это такое. Давайте попробуем System::DateTime, который не является примитивным типом значения:

DateTime dt = DateTime::Now;
DateTime^ dtbox = %dt;

Это работает!

В качестве еще одного досадного ограничения, примитивные типы, имеющие двойную идентичность (например, собственный int и управляемый тип значения System::Int32), обрабатываются неправильно, оператор % (ссылка на отслеживание формы) не может выполнять упаковку даже если имя .NET для типа задано .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...