我从C#代码中使用从C ++代码(LPSolve,参见http://lpsolve.sourceforge.net/5.5/)编译的dll。我使用API构建线性编程模型,然后解决它。我称之为以下函数:
[DllImport("lpsolve55.dll", SetLastError = true)]
public static extern bool add_columnex
(int lp, int count, double[] column, int[] rowno);
我想知道当我调用这样一个函数并且我在托管代码中创建的int和数组留下范围(在c#代码中)时会发生什么。他们是否有资格收集垃圾?这对c ++代码意味着什么?或者是不合格的,在那种情况下:为什么?
答案 0 :(得分:2)
因为函数原型使用普通的旧数据类型和数组,所以这些值的内存固定到位,然后本机代码直接作用于数据。然后当函数返回时,内存将被取消固定,并且可以进行垃圾回收。
换句话说,他们永远不会离开范围。
就C ++代码而言,如果它需要存储任何数据,那么它需要获取传递给它的数据的副本,然后自己管理该内存。
答案 1 :(得分:2)
我认为尼克已经涵盖了基本部分,这只是为了增加更多信息。 int / double数组被视为blittable类型(在托管/非托管世界中具有相同布局的类型) - 这些通常在Marshalled时被固定。所以你不必关于GC。此外,你所做的表示按值传递数组 - 在这种情况下,marshaller将其视为In参数 - 如果你的非托管dll将更新数组中的值,那么我建议你将其标记为In / Out参数(例如[In, Out]double[] column
)。欲了解更多信息:
答案 2 :(得分:1)
如果你的应用程序在使用它一段时间后(通过垃圾收集)没有因AccessViolationException而崩溃,那么可以非常安全地假设非托管代码制作了传递它的数组元素的副本。这是正常的事情,否则库也很难从本机代码中使用。还应该有一个API函数,可以让你清除或重新初始化模型,应该释放内存。
答案 3 :(得分:0)
C或C ++函数有这样的原型:
bool add_columnex(int lp, int count, double[] column, int[] rowno);
参数lp和count按值传递。参数列和rowno也按值传递,但实际数据通过引用传递,函数add_columnex
必须取消引用列和rowno。只有在函数调用期间才允许这种去引用。函数返回时,这些参数超出范围。这种脱离必须在界面的契约中。
当函数返回所有参数超出范围时,并不意味着函数在调用后可以执行任何操作。如果函数存储参数的副本,即double或rowno数组的地址,则必须由合同允许。在那种情况下你会遇到麻烦。更好的合同是函数必须复制解除引用的数据。