Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C#:如何访问C+上的托管2D阵列+-客户端? 我如何在C++端访问托管2D数组?< /P> 我知道我们应该使用 PixPtR ,以便从C++端访问托管数组。1D阵列很简单,但对于2D阵列,我不知道如何正确使用pin_ptr_C#_.net_Arrays_C++ Cli - Fatal编程技术网

C#:如何访问C+上的托管2D阵列+-客户端? 我如何在C++端访问托管2D数组?< /P> 我知道我们应该使用 PixPtR ,以便从C++端访问托管数组。1D阵列很简单,但对于2D阵列,我不知道如何正确使用pin_ptr

C#:如何访问C+上的托管2D阵列+-客户端? 我如何在C++端访问托管2D数组?< /P> 我知道我们应该使用 PixPtR ,以便从C++端访问托管数组。1D阵列很简单,但对于2D阵列,我不知道如何正确使用pin_ptr,c#,.net,arrays,c++-cli,C#,.net,Arrays,C++ Cli,我的代码如下所示,其中将从C#端调用foo(): nativeFunc(双**ptr); foo(数组^A) { const int len=A->GetLength(0); 双**ptr=(双**)alloca(sizeof(双*)*len); 对于(int i=0;iGetLength(0); m_dimInner=managedArray->GetLength(1); m_handle=GCHandle::Alloc(managedArray,GCHandleType::pinted);

我的代码如下所示,其中将从C#端调用
foo()

nativeFunc(双**ptr);
foo(数组^A)
{
const int len=A->GetLength(0);
双**ptr=(双**)alloca(sizeof(双*)*len);
对于(int i=0;i
问题是我的
pin_ptr
会过早超出范围,因为它位于循环体内部,因此我认为上面的代码不安全。但我怎样才能避免这种情况呢?显然,它不允许创建一个既不是托管的也不是非托管的
pin_ptr
数组。它也不能添加到
std::vector
,也不能成为类成员。所以我被困在这里了


谢谢你的建议……

好的,在进一步挖掘之后,我发现
GCHandle::Alloc(x,GCHandleType::pinted)
可以更灵活地替代这里的
pin\u ptr
。但是,我们似乎只能从整体上确定托管阵列。它确实似乎可以通过这种方式固定单个子阵列(内部阵列),就像
pin_ptr
一样。此外,通过“try-and-error”方法,我发现通过GCHandle句柄,我可以通过
hdl.AddrOfPinnedObject().ToPointer()
获得一个非托管指针,并且这个指针指向一个连续的内存块,该内存块以“展平”(序列化)形式包含整个2D数组。从这里,我可以通过使用适当的基指针和跨步重建非托管二维数组。但这被认为是一种“安全”的方法吗?它总是有效的吗?或者它甚至是特定于实现的吗


所以我拼凑了一个解决方案如下:

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;
};
类arraypinhanderraii
{
公众:
ArrayPinHandlerarii(数组^managedArray)
{
m_dimOuter=managedArray->GetLength(0);
m_dimInner=managedArray->GetLength(1);
m_handle=GCHandle::Alloc(managedArray,GCHandleType::pinted);
m_ptr=新双*[m_dimOuter];
double*basePointer=reinterpret\u cast
(m_handle.AddrOfPinnedObject().ToPointer());
对于(大小d=0;d

有什么意见吗?;-)好的,MSDN中的一个示例包含以下重要信息:

固定在托管对象中定义的子对象具有固定整个对象的效果例如,如果数组的任何元素被固定,则整个数组也被固定。声明固定数组的语言没有扩展。若要固定数组,请将固定指针声明为其元素类型,并固定其中一个元素

因此,代码实际上可以简化为:

void nativeFunc(double **ptr);

void foo(array<double,2> ^A)
{
    int dimOuter = managedArray->GetLength(0);
    int dimInner = managedArray->GetLength(1);

    pin_ptr<double> pinned = &A[i,0]; //This pins the *entire* array!

    double **ptr = (double**) alloca(sizeof(double*) * dimOuter); 
    double *basePtr = pinned;

    for(int i = 0; i < dimOuter; i++)
    {
       ptr[i] = basePtr;
       basePtr += dimInner;
    }

    nativeFunc(ptr);
}
void nativeFunc(双**ptr);
void foo(数组^A)
{
int-dimOuter=managedArray->GetLength(0);
int dimInner=managedArray->GetLength(1);
pin_ptr pinted=&A[i,0];//这将固定*整个*数组!
双**ptr=(双**)alloca(双*)尺寸*dimOuter;
双*basePtr=固定;
对于(int i=0;i
对于2D,您需要两个For循环(第二个循环替换
ptr[i]=pinted;
)。您现在指向的是来自长时间非托管内存(
ptr
)的特定于作用域的数据(
pind\u ptr pinted
),为什么我需要两个循环?对于1D数组,我根本不需要循环,因为
pin_ptr
给我一个指向数组数据的非托管指针。对于2D数组(即数组的数组),我需要循环,因为我需要迭代“外部”数组并接收指向每个“内部”数组的非托管指针。最大的问题是,
pin\ptr
只在数据超出范围之前固定数据,这是在我的循环的每次迭代之后如果不清楚,我的目标是获得指向数组数据的非托管
double**
指针,这是“本机”函数所需要的。我不想复制数据!只要
pin_ptr
在范围内,
pin_ptr
中的数据就有效。在上面的代码中,作用域在下一行(
}
)结束,之后不允许读/写指针。因此:1)您完全可以在
pin_ptr
处于活动状态时编辑数据。2) 要在处理
pin_ptr
后使用数据,您需要将该数据复制到自己的内存中(使用第二个for循环;或
memcpy
),我很清楚
pin_ptr
中的数据只要
pin_ptr
在范围内就有效。我想避免复制数据。这就是重点。无论如何,我在以下信息之一中发现:“固定在托管对象中定义的子对象具有固定整个对象的效果。例如,如果数组的任何元素被固定,那么整个数组也被固定。”因此
pin\u ptr
可以简单地位于循环之外,以完全避免“超出范围”的问题!看看我的另一个答案
void nativeFunc(double **ptr);

void foo(array<double,2> ^A)
{
    int dimOuter = managedArray->GetLength(0);
    int dimInner = managedArray->GetLength(1);

    pin_ptr<double> pinned = &A[i,0]; //This pins the *entire* array!

    double **ptr = (double**) alloca(sizeof(double*) * dimOuter); 
    double *basePtr = pinned;

    for(int i = 0; i < dimOuter; i++)
    {
       ptr[i] = basePtr;
       basePtr += dimInner;
    }

    nativeFunc(ptr);
}