我声明了以下结构(C ++):
struct NativeOperationResult {
const INTEROP_BOOL Success; // INTEROP_BOOL = char
const char16_t* const ErrorMessage;
NativeOperationResult(const NativeOperationResult& c);
/* various constructors, omitted for brevity */
};
现在,我在其他地方有一个导出的函数定义:
extern "C" __declspec(dllexport) NativeOperationResult ReturnFailureWithMessage() {
return { INTEROP_BOOL_FALSE, "Test" };
}
我的期望是从C#通过P / Invoke调用ReturnFailureWithMessage
(一种你想知道的测试方法)。在NativeOperationResult
构造函数中,它需要“Test”的副本并将其放在ErrorMessage
中。
NativeOperationResult拥有char16_t*
的所有权,因此我需要在销毁结构时删除它。这没问题,但我不想在.NET CLR有机会将字符串复制到托管堆之前删除内存。
坦率地说,我对删除内存的位置有点模糊。我认为C ++编译器会复制我的结构(或者只是移动它),然后CLR将使用该副本......这意味着我应该使用Marshal.FreeHGlobal
从.NET中删除本机内存。
这是对的吗?
答案 0 :(得分:1)
不,这不正确。您需要区分两种情况:
1)您没有在C ++端进行任何分配。 您正在讨论的情况。
2)你确实在C ++方面进行了分配,你需要处理重新分配。
这样回答你的问题:不,你的例子不需要任何“删除”内存,因为没有人明确地分配了内存。
第二种情况有点棘手。如果使用new char16_t[blah]
在C ++端进行内存分配,则需要使用delete[] nativeOperationResult.ErrorMessage
释放内存。这在C#方面是不可能的。可以使用不同的分配器(例如; malloc
,new
)分配内存,而C#不知道如何处理这些指针。
您需要向NativeOperationResult
添加新标记,例如DeletionRequired
,并从非托管端导出新功能:FreeNativeOperationResultIfNeeded(..)
。 There is longer discussion here
使用C ++ strings
可以避免所有这些无意义。它们神奇地工作,不需要删除。
struct NativeOperationResult {
const INTEROP_BOOL Success; // INTEROP_BOOL = char
const string const ErrorMessage;
NativeOperationResult(const NativeOperationResult& c);
/* various constructors, omitted for brevity */
};
答案 1 :(得分:0)
您可以将其设置为out参数,并期望调用方法向其传递适量的内存,而不是返回NativeOperationResult。这样,.Net可以分配内存,然后在pinvoke完成后清理它。但是你必须找到一种方法来通知.Net预期分配的内存量。
extern" C" __declspec(dllexport)void ReturnFailureWithMessage(NativeOperationResult * result)