Pregunta

I have a c++ function called innergetnum that gets as a parameter float& num

I write in managed c++ a function with the following code:

void getnum(float% num)
{
    innercppclass.innergetnum(num);
}

It doesn't work because he fails to convert num to float&

The only solution I found is to make additional temp variable float tmp, pass it to innergetnum and then to assign it to num.

Unfortunately I have many ref variables I want pass and the code looks ugly and I feel like the temp variable is a hack.

Is there a better way to solve it?

¿Fue útil?

Solución

error C2664: 'innercppclass::getnum' : cannot convert parameter 1 from 'float' to 'float &'
An object from the gc heap (a dereferenced gc pointer) cannot be converted to a native reference

You forgot to document the error you're dealing with, this is what you saw. This is entirely by design and fundamental to the way managed code works.

The float% argument of the managed function can be an interior pointer to a managed object, like the field of a ref class. The float& reference will be a raw unmanaged pointer at runtime, pointing to the float value. Which allows the callee to update the value. Both are just plain pointers at runtime, the only difference is that the garbage collector can see the interior pointer but not the unmanaged pointer. The jitter tells it where to look for the managed pointer, no such help for the native C++ function since it wasn't jitted.

So assigning the unmanaged pointer with the interior pointer value would be possible. However, something very nasty happens when the garbage collector runs while the native code is running. Note that a GC can occur when other threads in the program allocate memory. One important thing the GC does is compact the heap, it moves managed objects as part of the collection. A very desirable trait, it gets rid of the holes in the heap and makes managed code fast by improving locality of reference. Trouble is, the native code is holding a pointer to where that float used to be before it got moved. And if it writes through the pointer, updating the float value, it will corrupt the GC heap.

There isn't any way that the GC can stop the native code from doing this, it doesn't know where the pointer value is located in memory so it cannot update it. No such trouble with the interior pointer but an unsolvable problem for the native reference.

So the compiler complains, it can't possibly generate code that won't crash your program sooner or later (usually later) with completely undiagnosable heap damage. You already found the workaround, you need to generate the pointer from a storage location that is not the GC heap. The stack is fine, local variables never move:

void Managed::getnum(float% num) { 
    float temp;
    innercppclass::getnum(temp); 
    num = temp;
}

Otherwise the kind of code you'd write as well when you turn void getnum(float%) into float getnum(). Or more typically in managed code, a property getter:

property float num {
    float get() { 
        float temp;
        innercppclass::getnum(temp); 
        return temp;
    }
}

Nothing much else you can do about it, it is a very fundamental restriction.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top