[C++ CLI] почему нельзя брать адрес pin_ptr'а на нативный объект?
Имо, потому что он не в управляемой куче и закреплять его незачем.
И, кстати, pin_ptr'ы в куче нельзя располагать:
Pinning pointers can only be declared as non-static local variables on the stack.
Я понятия не имею, как оно работает, но допускаю, что дико виртуально и синтактически-сахарно.
И, кстати, ты уверен, что правильно понимаешь, о чём речь вообще? Адрес у пойнтера андефайнд, а не у объекта, на который он указывает.
с момента присваивания такому указателю чего-то и до выхода из текущего блока кода (мы же только в стеке можем быть) объект, на который указывает _он_, оказывается фиксирован в управляемой куче.
соответственно, если туда пихать указатели на объекты не из управляемой кучи, получится неизвестно что, потому и непредсказуемы последствия.
в более дружественном к .NET языке C# есть специальная конструкция - fixed, которая делает тоже самое, но при этом явно ограничивает область своего действия оператором (или блоком следующим за "заголовком".
если туда пихать указатели на объекты не из управляемой кучи, получится неизвестно чтоВполне известно, что получится:
не понятно только, почему нельзя брать адрес этого пин_птра и именно когда в него запихнут неуправляемый объект.
A pin_ptr represents a superset of the functionality of a native pointer. Therefore, anything that can be assigned to a native pointer can also be assigned to a pin_ptr.
Может, потому что его нет? Типа, соптимизён нафиг?я думал, что оптимизация не должна оказывать такое влияние на спецификацию.
так можно дойти до того, что ни у каких объектов нельзя будет адрес брать: вдруг соптимизят!
И, кстати, ты уверен, что правильно понимаешь, о чём речь вообще? Адрес у пойнтера андефайнд, а не у объекта, на который он указывает.Ну, вроде понимаю... Адрес у объекта указателя вполне себе дефайнед, вроде.
не понятно только, почему нельзя брать адрес этого пин_птра и именно когда в него запихнут неуправляемый объект.Какой будет тип у этого указателя?
кстати есть уверенность, что pin_ptr - это именно указатель, а не "объект" с несколькими полями?
pin_ptr<type>* ?
> кстати есть уверенность, что pin_ptr - это именно указатель, а не "объект" с несколькими полями?
Как раз наоборот, есть почти уверенность, что это объект. Хотя бы потому что у него деструктор нетривиальный.
pin_ptr<type>* ?и что ты будешь делать с таким указателем?
> Как раз наоборот, есть почти уверенность, что это объект. Хотя бы потому что у него деструктор нетривиальный
тогда получается, что имея указатель на этот объект ты можешь легко порушить его состояние.
зы
самое главное, а для каких операций тебе нужен указатель на pin_ptr?
так может и хотелось, чтобы ты задумывался, когда такие операции хочешь провести над pin_ptr?
какая разница? какое это имеет отношение к сути вопроса?
> тогда получается, что имея указатель на этот объект ты можешь легко порушить его состояние.
да я вообще много чего гадкого могу сделать: записать случайные байты по случайному адресу, но никакая спецификация CLI C++ этого не запрещает.
> самое главное, а для каких операций тебе нужен указатель на pin_ptr?
да кто тебе сказал, что он мне вообще нужен? =)
просто запрет этот выглядит довольно странным.
не очень понятно, как на этапе компилляции определить, на какой объект указывает pin_ptr: managed или unmanaged.
было бы здорово, если бы определённость поведения при выполнении операции не зависела от логики программы.
или хотя бы было разумное объяснение, почему этого нельзя добиться.
я такого объяснения не вижу на данный момент, поэтому мне кажется, что я чего-то не понимаю.
вот я и хочу понять, чего.
ответы типа "навига тебе это нужно?" к пониманию не приводят как-то...
Мне кажется, что в манагед С++ присутствует определённая шизофрения, которую нужно учитывать. Манагед код компилится и исполняется в CLI. Там pinned pointer не отличается от обычного референса ничем, кроме того, что он pinned (то есть помечен как таковой в какой-то внутренней табличке GC но можно вызывать его методы специфическим образом, так же, как они вызываются для value types — когда this просто указывает на кусок памяти, без каких-либо метаданных. Понимаешь?
А вот указатель на анманегед ресурсы — это уже совсем-совсем не референс. То есть внутри он такой же указатель, но если ты стайпкастишь его к настоящему pinned_ptr, то тебя могут ожидать страшные сюрпризы. Потому что pinned_ptr может обращаться к GC за разъяснениями, а эта штука будет вести себя непредсказуемо. Эммм... Хотя причём тут его личный адрес... Прозреваю, что дело всё-таки в оптимизации. Довольно многие люди объявляли некое никому не нужное поведение неправильным, implementation dependent и всё такое из соображений оптимизации!
Вообще я в этом страшно неуверен и написал только с той целью, чтобы тред остался наверху и какой-нибудь гуру C++CLI зашёл и всё объяснил!
Тут поподробней, плиз. Какие методы? И в чём специфичность образа их вызова?
> this просто указывает на кусок памяти, без каких-либо метаданных.
Я думал, что value-типы отличаются от reference-типов только расположением в памяти и, соответственно способом доступа к ним.
А метаданные там есть так же, как и в референсных типах.
> Вообще я в этом страшно неуверен и написал только с той целью, чтобы тред остался наверху и какой-нибудь гуру C++CLI зашёл и всё объяснил!
+1
У reference-type указатель указывает на сложную структуру в которой есть указатель на тип (то есть на другую сложную структуру). Это и в плюсах так, кстати. То есть если ты напишешь
object zzz = new System.Int32(42);
после чего попытаешься посмотреть на память, на которую реально указывает локальная переменная zzz, то увидишь там множество всякой фигни, кроме числа 42. Которая нужна для того, чтобы ты потом мог zzz куда-нибудь передать и там вызвать GetType (виртуально унаследованный от Object). Да, если чо, таким образом созданный инт является reference-type. Он, типа, boxed.
У value-type ничего такого нет, указатель указывает сразу на данные. Потому что (или поэтому) наследоваться от value-types нельзя. То есть все вызываемые методы резолвятся в конкретные адреса на этапе компиляции, а передаётся им в качестве нулевого параметра указатель на данные.
То есть в случае value-types ты получаешь видимость ООП, хотя из четырёх его свойств реализуется только одно, инкапсуляция. Зато удобно и быстро, что уж тут. Типа, синтаксический сахар: у тебя где угодно есть четыре байта и ты вместо вызова статического метода, которому они передаются, вызываешь как бы метод класса (которому они точно так же за кадром передаются, но ты этого не видишь).
Вот. Мне кажется, что где-то тут и скрыт ответ на твой вопрос. Что, типа, если всё известно на этапе компиляции, то открываются широчайшие просторы для оптимизации — вплоть до того, что память под pinned_ptr не будет выделена вообще. А зачем она? У тебя уже есть указатель, который ты передал в конструктор pinned_ptr, нафига его дублировать? И, в случае если это был managed указатель, компилятор корректно перенаправит обращения к нему (в том числе и взятие адреса) к тому реальному указателю. А специально для корректной обработки случая unmanaged указателей никто код писать не хочет.
Managed указатель это пойнтер или хэндл? То есть, это реально адрес, или инт, являющийся индексом ячейки в какой-то внутренней хештейбле, в которой лежит адрес? Типа, GC же периодически компактит память, ему, наверное, было бы сложно отслеживать все указатели на данный кусок, чтобы их исправить, гораздо легче исправить один раз в той хэштейбле. За счёт не очень больших тормозов в рантайме, потому что используемые в данный момент элементы можно как-то помечать, чтобы их GC не попортил, а если захочет попортить, то найдёт где их изменить во всех остальных местах, а тогда реальные адреса можно эффективно кэшировать.
Потому что (или поэтому) наследоваться от value-types нельзя.угу, забыл, что наследоваться от value-типов нельзя, тогда, конечно, нет смысла метаданные с собой таскать
если всё известно на этапе компиляции, то открываются широчайшие просторы для оптимизации — вплоть до того, что память под pinned_ptr не будет выделена вообщенаверно, но если так рассуждать, то нужно операцию взятия адреса отменить вообще.
А специально для корректной обработки случая unmanaged указателей никто код писать не хочет.
ну... хочет-не хочет, а писать всё равно придётся. =)
pin_ptr<int> p;
if (use_managed)
p = &managed_i;
else
p = &unmanaged_i;
*p = 500;
Оставить комментарий
psihodog
Кто-нть может пояснить смысл этой фразы из MSDN'а:?