如何避免回调函数中的RuntimeWarning内存泄漏(Python回调将字符串返回给C)? C++库
CallbackTestLib.hpp如何避免回调函数中的RuntimeWarning内存泄漏(Python回调将字符串返回给C)? C++库,python,visual-c++,memory-leaks,callback,ctypes,Python,Visual C++,Memory Leaks,Callback,Ctypes,CallbackTestLib.hpp #include <iostream> using namespace std; typedef void (*CB)(char* buf,size_t len); extern "C" __declspec(dllexport) int func(CB cb) { char buf[80]; if(cb) { cb(buf,sizeof buf); cout <&l
#include <iostream>
using namespace std;
typedef void (*CB)(char* buf,size_t len);
extern "C" __declspec(dllexport) int func(CB cb) {
char buf[80];
if(cb) {
cb(buf,sizeof buf);
cout << "Hello " << buf << endl;
return 1234;
}
return 5678;
}
#pragma一次
使用callback_prototype=const char*_cdecl();
外部“C”declspec(dllexport)int cdecl do_something(回调原型*);
CallbackTestLib.cpp
#include <iostream>
using namespace std;
typedef void (*CB)(char* buf,size_t len);
extern "C" __declspec(dllexport) int func(CB cb) {
char buf[80];
if(cb) {
cb(buf,sizeof buf);
cout << "Hello " << buf << endl;
return 1234;
}
return 5678;
}
#包括“CallbackTestLib.hpp”
#包括
使用名称空间std;
__declspec(dllexport)auto\uu cdecl do\u something(callback\u prototype*cb)->int
{
如果(!cb){return 5678;}
const auto*str=cb();
cout这对我来说还是有点模糊/不清楚。但这里有一个愚蠢的修复(我不满意),它让memleak警告信息消失了:
版本1
CallbackTestLib.hpp
#include <iostream>
using namespace std;
typedef void (*CB)(char* buf,size_t len);
extern "C" __declspec(dllexport) int func(CB cb) {
char buf[80];
if(cb) {
cb(buf,sizeof buf);
cout << "Hello " << buf << endl;
return 1234;
}
return 5678;
}
#pragma一次
使用callback_prototype=void*u cdecl();//将“const char*”更改为“void*”。
外部“C”declspec(dllexport)int cdecl do_something(回调原型*);
CallbackTestLib.cpp
#include <iostream>
using namespace std;
typedef void (*CB)(char* buf,size_t len);
extern "C" __declspec(dllexport) int func(CB cb) {
char buf[80];
if(cb) {
cb(buf,sizeof buf);
cout << "Hello " << buf << endl;
return 1234;
}
return 5678;
}
#包括“CallbackTestLib.hpp”
#包括
使用名称空间std;
__declspec(dllexport)auto\uu cdecl do\u something(callback\u prototype*cb)->int
{
如果(!cb){return 5678;}
const auto*str=cb();
cout这对我来说还是有点模糊/不清楚。但这里有一个愚蠢的修复(我不满意),它让memleak警告信息消失了:
版本1
CallbackTestLib.hpp
#include <iostream>
using namespace std;
typedef void (*CB)(char* buf,size_t len);
extern "C" __declspec(dllexport) int func(CB cb) {
char buf[80];
if(cb) {
cb(buf,sizeof buf);
cout << "Hello " << buf << endl;
return 1234;
}
return 5678;
}
#pragma一次
使用callback_prototype=void*u cdecl();//将“const char*”更改为“void*”。
外部“C”declspec(dllexport)int cdecl do_something(回调原型*);
CallbackTestLib.cpp
#include <iostream>
using namespace std;
typedef void (*CB)(char* buf,size_t len);
extern "C" __declspec(dllexport) int func(CB cb) {
char buf[80];
if(cb) {
cb(buf,sizeof buf);
cout << "Hello " << buf << endl;
return 1234;
}
return 5678;
}
#包括“CallbackTestLib.hpp”
#包括
使用名称空间std;
__declspec(dllexport)auto\uu cdecl do\u something(callback\u prototype*cb)->int
{
如果(!cb){return 5678;}
const auto*str=cb();
CUT< P>有Python回调返回一个代码> char */COD>类似于C++函数返回:
char* callback() {
return new char[10];
}
除非内存释放,否则内存泄漏。因为Python分配了字节对象,C++不能正确地释放它,因此泄漏。
而是将C++管理的缓冲区传递给回调:
测试.cpp
#include <iostream>
using namespace std;
typedef void (*CB)(char* buf,size_t len);
extern "C" __declspec(dllexport) int func(CB cb) {
char buf[80];
if(cb) {
cb(buf,sizeof buf);
cout << "Hello " << buf << endl;
return 1234;
}
return 5678;
}
输出:
Hello world!
1234
具有Python回调返回一个代码> char */COD>类似于C++函数返回:
char* callback() {
return new char[10];
}
除非内存释放,否则内存泄漏。因为Python分配了字节对象,C++不能正确地释放它,因此泄漏。
而是将C++管理的缓冲区传递给回调:
测试.cpp
#include <iostream>
using namespace std;
typedef void (*CB)(char* buf,size_t len);
extern "C" __declspec(dllexport) int func(CB cb) {
char buf[80];
if(cb) {
cb(buf,sizeof buf);
cout << "Hello " << buf << endl;
return 1234;
}
return 5678;
}
输出:
Hello world!
1234
在返回之前,您可能需要释放str
:delete[]str;
@Mike67刚刚尝试过,没有修复它。它是ctypes
,而不是cpptypes
,所以可能是free()
假设DLL和Python是使用相同的C运行库构建的,则可以工作。但真正的解决方案是不返回char*
ctypes
如果值返回到C/C++代码,我不知道如何减少回调返回的Python对象的引用计数。@MarkTolonen我找不到任何关于的信息de>cpptypes
这是从哪里来的?Python为什么会关心CData上的refcount(c\u char\u p/bytes)的递减?如果我不返回const char*
,那么我是什么…?我是说cpptypes
不存在…所以ctypes
(一个“c”包装器)可能会在内部使用malloc/free
“新增/删除"。当您从Python函数返回对象时,Python会在内部将引用计数增加到返回的对象;否则,当函数返回时,本地对象将被释放。但是您将对象返回到C代码,而不是Python,因此ctypes
将获得指向Python对象缓冲区的char*
指针,并且C代码无法减少Python ref,因此出现泄漏。ctypes
也无法减少ref,否则char*
将无效。您可能需要在返回之前释放str
:delete[]str;
@Mike67刚刚试过,还没修好。它是ctypes
,不是cpptypes
,所以可能是free()
假设DLL和Python是使用相同的C运行库构建的,则可以工作。但真正的解决方案是不返回char*
ctypes
如果值返回到C/C++代码,我不知道如何减少回调返回的Python对象的引用计数。@MarkTolonen我找不到任何关于的信息de>cpptypes
这是从哪里来的?Python为什么会关心CData上的refcount(c\u char\u p/bytes)的递减?如果我不返回const char*
,那么我是什么…?我是说cpptypes
不存在…所以ctypes
(一个“c”包装器)可能会在内部使用malloc/free
“新增/删除"。当您从Python函数返回对象时,Python会在内部将引用计数增加到返回的对象;否则,当函数返回时,本地对象将被释放。但是您将对象返回到C代码,而不是Python,因此ctypes
将获得指向Python对象缓冲区的char*
指针,并且C代码不能减少Python ref,因此存在漏洞。ctypes
也不能减少ref,否则char*
将无效。在这种情况下,您将传回一个数字(avoid*
address`).Python可能会释放字符串的内存,幸运的是地址仍然包含数据(调用了未定义的行为!)。相反,请将一个C管理的缓冲区传递给回调,并返回其中的字符串。我将发布一个示例。@MarkTolonen我提出了另一种方法(V2),您能看看吗?(仍然不满意。)除了线程不安全之外,它看起来还不错。\u strdup()
应该使用free()
释放