Passing a tracking handle as a void*

こ雲淡風輕ζ 提交于 2020-01-25 03:43:06

问题


I'm interfacing the statistical language R direcly from .NET using managed c++. I'm a little green in Managed C++, and I need to do something a little tricky. A structure use to pass to a function has a generic data pointer void*used to pass some payload data usable in a later callback. Hope I explained, is a pretty well used pattern in C/C++. But for my use I need to pass a managed object by using that void *, how can I do?

I'm trying with:

BinaryWriter^ bs=gcnew......;
stream->data=(void*)(%bs);

but it does not work. Any help?

UPDATE This seems to work, but not sure if it is the best way:

pin_ptr<BinaryWriter^> p = &bs;
stream->data=(void*)p;

回答1:


The C++/CLI compiler stops you from doing this, that will grossly mis-behave at runtime. The point of a "tracking handle" is that the garbage collector can find the pointer back and update its value when it moves the object when it compacts the heap. It cannot do this when you cast it to void* and pass that pointer to native code. That native code will continue using the object after the garbage collection as though it is still in its original location. That's disastrous.

Yes, using pin_ptr<> is a workaround, that pins the object so it cannot be moved. It will only stay pinned as long as the scope block in which the pin_ptr<> is declared executes so be sure that the native code cannot still dereference that pointer later. You get a more permanent pin with GCHandle::Alloc(), passing GCHandleType::Pinned. GCHandle::AddrOfPinnedObject() returns the pointer value.

Do take a step back, you want to pass a pointer to a managed object that can only ever be called from managed code. In other words, there's nothing that native code can actually do with that void*.




回答2:


You probably want to use an IntPtr type.




回答3:


My C++/CLI is a little rusty (so there may be a better way to do this, it may be that pin_ptr is just be short hand for the following) but using GCHandle is the standard when in C#.

// getting a fixed pointer
BinaryWriter^ bs=gcnew......;
GCHandle handle = GCHandle.Alloc(bs, GCHandleType.Pinned);
IntPtr ptr = GCHandle.ToIntPtr(handle);

// in callback
GCHandle handle = GCHandle.FromIntPtr(ptr);
BinaryWriter^ bs = (BinaryWriter^)handle.Target;
handle.Free();

Of course IntPtr can be cast to a void* and back again.



来源:https://stackoverflow.com/questions/18999592/passing-a-tracking-handle-as-a-void

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!