Помните, что основное использование 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 для типа задано .