CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 3 of 3
  1. #1
    Join Date
    Oct 2014
    Posts
    13

    How to access a managed 2D array in C++ *without* making a deep copy?

    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.

  2. #2
    Join Date
    Jan 2010
    Posts
    1,133

    Re: How to access a managed 2D array in C++ *without* making a deep copy?

    Here's what I've found on this page.

    Pinning a sub-object defined in a managed object has the effect of pinning the entire object. For example, if any element of an array is pinned, then the whole array is also pinned. There are no extensions to the language for declaring a pinned array. To pin an array, declare a pinning pointer to its element type, and pin one of its elements.
    It seems that you can simply pin an arbitrary element of the array outside of your loop, and the entire array will be pinned - so you don't really need pinned pointers to the elements, you just need the addresses.
    HTH

  3. #3
    Join Date
    Oct 2014
    Posts
    13

    Re: How to access a managed 2D array in C++ *without* making a deep copy?

    Thank you for pointing my at that example! That is very valuable information.

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured