На этом шаге мы приведем программу, реализующую указанное преобразование.
Дескрипторами называют указатели в среде CLR. Именно они указывают на объект в управляемой куче. Напрямую нельзя объявить дескриптор в native-типе. Например, в native-функции вы не можете сделать объявление типа такого:
String^ s;
Компилятор вам выдаст ошибку. Файл vcclr.h содержит специальный настраиваемый шаблон gcroot, позволяющий ссылаться на CLR-объекты из C++ кучи, т. е. объекты из неуправляемой кучи могут ссылаться на объекты из управляемой кучи. Тем самым устанавливается связь между различными средами. При этом вам позволяется использовать дескриптор в native-типе (например, в функции) и трактовать его как основной тип.
Шаблон gcroot создан на основе класса:
System::Runtime::InteropServices::GCHandle ,
Отметим, что сами дескрипторы автоматически удаляются деструктором класса gcroot только тогда, когда они больше не используются. Их нельзя удалять вручную. Если же вы создаете gcroot-объект в native-куче (т. е. в неуправляемой), то должны сами вызвать оператор delete для освобождения ресурса.
В режиме исполнения программы поддерживается постоянная связь между дескриптором и CLR-объектом, на который он указывает. Если объект по тем или иным причинам перемещается в куче, дескриптор всегда возвращает новый адрес объекта. Переменная не может получить pin-указатель (предохраняющий объект от перемещения в такой куче), пока она назначена шаблону gcroot.
Текст программы приведен ниже, а результат - на рисунке 1.
// 223_1.cpp: главный файл проекта. #include "stdafx.h" #include <vcclr.h> using namespace System; // reference_to_value_in_native.cpp // compile with: /clr public value struct V //CLR-структура { String^ str; }; class Native //native-класс { public: //член native-класса - дескриптор v_handle: gcroot< V^ > v_handle; }; void main() { Native native; //native-переменная, объявленная в managed-функции V v; //managed-переменная //дескриптору присваивается значение v, //т.е. формируется ссылка на managed-структуру, // из которой теперь можно извлекать ее элементы: native.v_handle = v; native.v_handle->str = "Hello to all"; Console::WriteLine("String in V: {0}", native.v_handle->str); Console::ReadLine(); }
Рис.1. Работа с дескриптором в native-памяти
На следующем шаге мы рассмотрим работу с дескриптором в native-функции.