• Advertisement
Sign in to follow this  

[.net] Array hackishness. Good idea or asking for trouble?

This topic is 4783 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I've been writing some .NET wrappers of some old Win32 API components for my personal use, but some unmanaged methods required unmanaged buffers of data, which meant I either had to copy the buffers from managed memory (somewhat time-consuming and uses twice as much memory) or pin the buffers, sometimes for long periods of time (which had negative effects on garbage collection speed). Out of frustration, I wrote a little function to give me a sort of hybrid array that can act like either an unmanaged pointer or a managed array. The buffer actually lives in unmanaged memory to keep it fixed, but a psuedo-managed array is created at the same time to make the array available to managed methods. (Note that because it resides in unmanaged space it needs to be freed explicitly at some point to prevent memory leaks.) My main concern is whether the garbage collector is going to get confused at any point if/when it sees an array that it wasn't told to track. I tested out the "array"/pointer on a few managed and unmanaged methods and it seemed to work okay, but I'm not sure if this will always be the case or not. Below is the source (in C++/CLI):
//A method that returns the managed array handle and passes back a pointer to the array by a reference
template <typename T>
array<T>^ CreateFixedArray(unsigned int length, T*& ptr) {

	//Create a real managed array with no contents
	array<T>^ hArr = gcnew array<T>(0);
	//Get the virtual function table pointer from the real array
	unsigned int vt = **((unsigned int**) &hArr);
	//We're done with the real array
	hArr = nullptr;
	//Allocate (and clear) enough unmanaged space for the array
	void* arr = (T*) calloc(sizeof(T) * length + 8, 1);
	//Assign the unmanaged data to the pointer (with an offset of 8 bytes so the managed array can have the info it needs)
	ptr = (T*) ((unsigned int*) arr + 2);
	//Assign the virtual function table recorded earlier to the psuedo-array
	*((unsigned int*) arr) = vt;
	//Assign length information to the psuedo-array
	*((unsigned int*) arr + 1) = length;
	//Place the reference to the psuedo-array in the array handle
	*((void**) &hArr) = arr;
	//Return the handle
	return hArr;

//This function accepts an array that was created with the CreateFixedArray function
void DeleteFixedArray(Array^ arr) {
	//Cast the handle back to a void pointer
	void* ptr = *reinterpret_cast<void**>(&arr);
	//Free the memory pointed to

Is this going to work alright, or am I asking for problems later on?

Share this post

Link to post
Share on other sites
It's a mess and will blow up sooner or later. E.g., managed objects have more overhead than only a vptr. There's also a SyncBlockIndex which is used for synchronizing objects. Furthermore assuming that the vptr is 4 byte is risky. And messing with the interiors of managed objects is generally a bad idea.

So, try some more conversative ways of interop. Have you actually MEASURED that pinning the arrays increased GC time?


Share this post

Link to post
Share on other sites
I haven't tried the pinning pointers since I was using C#, but another problem I encountered with them was that as soon as the method scope was left, the object didn't remain fixed. Does this still apply in C++/CLI, or can I have an object pinned longer than the method scope in which the pointer was created? The code I posted above could be changed, of course, if it would give it a bit more robustness (using a native sized integer instead of 4 byte, etc). Is there anything that could give the code a better chance of success, or is an attempt to make a psuedo-managed object pretty much doomed to fail?

Share this post

Link to post
Share on other sites
Sign in to follow this  

  • Advertisement