【发布时间】:2015-10-20 09:21:00
【问题描述】:
我们有一个 c# 应用程序,它使用回调方法从 c++ 项目接收数据:
/* c# code */
call[UnmanagedFunctionPointer(CallingConvention.StdCall)]
private unsafe delegate void NewFrame(string serial, Int32* width, Int32* height, short* frame);
在我们的 C++ 项目(从相机接收数据)中,我们非常频繁地调用这个“NewFrame”回调方法,将相机帧传递给 c# 代码。
这个方法在c++中的定义是:
/* c++ code */
typedef void (__stdcall * NewFrame)(char* serialnumber, INT32* width,INT32* height, int16_t* frame);
要传递“序列”,在 c++ 代码中将 c++ 字符串对象转换为 char*:
/* c++ code */
char* stringToCsharpString(string s){
char* cserial = new char[s.length() + 1];
strcpy(cserial, s.c_str());
return cserial;
}
但是,这会导致(堆)内存泄漏,因为 cserial 对象没有被释放。
这是在 c++ 中调用这个 NewFrame 方法的方式:
/* c++ code */
newFrame(stringToCsharpString(node.getSerialNumber()), &w, &h, data.frame);
我们可以做些什么来解决这个问题?我们精通c#,但一点也不精通c++。所以说c++代码的时候,请解释清楚:)
【问题讨论】:
-
需要在c#包装对象的Dispose()方法中删除这个动态内存
-
它还取决于 NewFrame 对字符串的处理方式。如果访问是只读的和同步的,并且指针没有存储在任何地方(即调用者等待完成并且
NewFrame()以某种方式复制和/或转换数据),您可以只使用s.c_str()作为参数。 -
无论如何,您都不应该跨模块边界传递诸如
std::string之类的类。 C# 对std::string及其内部实现等一无所知。NewFrame的参数应该只是指向 C# 创建的字符缓冲区(数组)的指针,不多也不少。 -
@PaulMcKenzie 只是为了避免误解——你的意思是参数应该是 C# 创建的缓冲区(而不是 C++,它是这里的调用者,数据的来源)?如果我们假设暂时使用在 C++ 端创建的缓冲区:
s.c_string()将符合“仅作为指向字符缓冲区的指针”的要求,因此您的(明智的)警告不会禁止它通过C++std::strings。我们同意吗? -
@RonaldoMessi 我将如何删除这段记忆?我在 C# 中得到的只是一个字符串对象
标签: c# c++ memory-leaks