dllexport中丢失了指针引用

时间:2018-07-11 19:08:02

标签: c# c++ pinvoke dllexport

我正在尝试从我的C#代码中调用CPP方法,该方法将返回以下结构。

CPP:

struct ArrayD
{
int count;
float* arrayData;
}

C#:

struct ArrayD
{
int count;
IntPtr arrayData;
}

使用CPP代码中的std :: make_unique初始化数组,并返回结构。

但是当我尝试使用Marshal.Copy将IntPtr复制到C#中的float数组时,我尝试读取/写入损坏的内存错误。

我确认在dll导出过程中丢失了对数组的引用,有没有办法在整个代码中保留引用或数据。

下面是代码

extern "C" ArrayD _declspec(dllexport) __stdcall  CPPMetho()
    {
        auto arrayd  = std::make_unique<ArrayD>();
        arrayd.count = 10;

        auto arrayData = std::make_unique<float[]>(arrayd.count);

// Fill data to the array created above

        arrayd.arrayData= arrayData .get();

        return arrayd;
    }

我在C#代码中调用上述API,我从数组中获得“计数”的值,但是当我尝试封送数组数据时,我得到了异常。

任何想法如何将引用保留在C#中以启用封送处理

2 个答案:

答案 0 :(得分:0)

这两行是问题所在:

auto arrayData = std::make_unique<float[]>(arrayd.count);

arrayd.arrayData= arrayData .get();

第一个创建包裹数组的智能指针。第二行保存指向包装好的数组的指针。

然后,当您从函数返回时,arrayData的生存期结束并且被破坏,然后释放包装的数组。这使您保存的指针无效,因为它现在指向未分配的内存。

解决方案是在结构中也使用智能指针,或者更好的方法是使用std::vector<float>(在这种情况下,您根本不需要结构)。

答案 1 :(得分:0)

最少的更改是:

ArrayD arrayd = {};
arrayd.count = 10;

// std::unique_ptr<float[]> arrayData
// don't let auto hide what the types really are!
auto arrayData = std::make_unique<float[]>(arrayd.count);

// Fill data to the array created above

arrayd.arrayData = arrayData.release();
return arrayd;

请注意,我已经更改了arrayd的分配。现在,它是一个堆栈变量。并且为arrayData添加了release(),以使std::unique_ptr<>创建的std::make_unique<float[]>不会被释放。您必须创建一个伴随FreeArrayD(ArrayD& arrayData)来释放分配的内存。