Hello.

What is the recommended way to access a managed 2D on the C++ side without having to make a deep copy?

Scenario is as follows: The C++/CLI function that will be called from the C# side has a signature of foo(array<double,2> A) and the native C function I need to call is bar(double **ptr).

With a 1D array things are straightforward with pin_ptr<T> magic:
Code:
void bar(double *ptr);
void foo(array<double> ^A)
{
   pin_ptr<double> pinned = &A[0];
   double *ptr = pinned;
   bar(ptr);
}
But as soon as I have a 2D array, I have a problem with pin_ptr<T>, because it will go out of scope too early:
Code:
void bar(double **ptr);
void foo(array<double,2> ^A)
{
    const int len = A->GetLength(0);
    double **ptr = (double**) alloca(sizeof(double*) * len);
    for(int i = 0; i < len; i++)
    {
       pin_ptr<double> pinned = &A[i,0]; //Will go out of scope at end of loop body!
       ptr[i] = pinned;
    }
    bar(ptr); //Not save <-- pinned pointers have been released already :-(
}
So what is the recommended way to go here?

I cannot retain my pin_ptr<T>'s, since VS says I cannot make an array (neither managed nor unmanaged) of this type. Nor can it be in a STL container

------------------

After some digging, I found out that GCHandle::Alloc(x, GCHandleType::Pinned) may work as a more flexible replacement for pin_ptr<T> here. However, it seems we can only pin down the managed array as a whole. It does not seem to be possible to pin down a single sub-array (inner array) this way, like the pin_ptr<T> would do. Furthermore, by "try and error" method I have figured out that from the GCHandle I can get an unmanaged pointer via h.AddrOfPinnedObject().ToPointer() and that this one points to a continuous block of memory which contains the whole 2D array in a "flattened" (serialized) form. From here I can reconstruct the unmanaged 2D array, by using the proper base-pointer and stride. But is this considered a "safe" method and does it always work or is it even implementation specific?

What I currently use looks like this:
Code:
class ArrayPinHandlerRAII
{
public:
    ArrayPinHandlerRAII(array<double,2> ^managedArray)
    {
        m_dimOuter = managedArray->GetLength(0);
        m_dimInner = managedArray->GetLength(1);

        m_handle = GCHandle::Alloc(managedArray, GCHandleType::Pinned);
        m_ptr = new double*[m_dimOuter];
        double *basePointer = reinterpret_cast<double*>
            (m_handle.AddrOfPinnedObject().ToPointer());

        for(size_t d = 0; d < m_dimOuter; d++)
        {
            m_ptr[d] = basePointer;
            basePointer += m_dimInner;
        }
    }

    ~ArrayPinHandlerRAII(void)
    {
        delete [] m_ptr;
        m_handle.Free();
    }

    inline double **data(void)
    {
        return m_ptr;
    }

    inline const size_t &dimOuter(void) const
    {
        return m_dimOuter;
    }

    inline const size_t &dimInner(void) const
    {
        return m_dimInner;
    }

private:
    GCHandle m_handle;
    double **m_ptr;
    size_t m_dimOuter;
    size_t m_dimInner;
};
Code:
void bar(double **ptr);
void foo(array<double,2> ^A)
{
    ArrayPinHandlerRAII myPinnedArray(A)
    bar(myPinnedArray.data());
}
What do you think about this method?

Regards.