Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/360.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何避免回调函数中的RuntimeWarning内存泄漏(Python回调将字符串返回给C)? C++库_Python_Visual C++_Memory Leaks_Callback_Ctypes - Fatal编程技术网

如何避免回调函数中的RuntimeWarning内存泄漏(Python回调将字符串返回给C)? C++库

如何避免回调函数中的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

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=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*
将无效。在这种情况下,您将传回一个数字(a
void*
address`).Python可能会释放字符串的内存,幸运的是地址仍然包含数据(调用了未定义的行为!)。相反,请将一个C管理的缓冲区传递给回调,并返回其中的字符串。我将发布一个示例。@MarkTolonen我提出了另一种方法(V2),您能看看吗?(仍然不满意。)除了线程不安全之外,它看起来还不错。
\u strdup()
应该使用
free()
释放