我有一个swigged C ++类容器, MyContainer ,持有 MyObject 类型的对象,也是一个C ++类。
以下是C ++标头代码( freemenot.h )
#ifndef freemenotH
#define freemenotH
#include <vector>
#include <string>
using std::string;
class MyObject
{
public:
MyObject(const string& lbl);
~MyObject();
string getLabel();
private:
string label;
};
class MyContainer
{
public:
MyContainer();
~MyContainer();
void addObject(MyObject* o);
MyObject* getObject(unsigned int t);
int getNrOfObjects();
private:
std::vector<MyObject*> mObjects;
};
#endif
这是源( freemenot.cpp )
#include "freemenot.h"
#include <iostream>
using namespace std;
/* MyObject source */
MyObject::MyObject(const string& lbl)
:
label(lbl)
{ cout<<"In object ctor"<<endl; }
MyObject::~MyObject() { cout<<"In object dtor"<<endl; }
string MyObject::getLabel() { return label; }
/* MyContainer source */
MyContainer::MyContainer() { cout<<"In container ctor"<<endl; }
MyContainer::~MyContainer()
{
cout<<"In container dtor"<<endl;
for(unsigned int i = 0; i < mObjects.size(); i++)
{
delete mObjects[i];
}
}
int MyContainer::getNrOfObjects() { return mObjects.size(); }
void MyContainer::addObject(MyObject* o) { mObjects.push_back(o); }
MyObject* MyContainer::getObject(unsigned int i) { return mObjects[i]; }
观察对象在向量中存储为 RAW POINTERS 。这个类是这样设计的,因此容器负责释放析构函数中的对象,就像在循环的析构函数中完成一样。
在C ++代码中,如下所示,将对象o1添加到容器c中,并将其返回给客户端代码
MyContainer* getAContainerWithSomeObjects()
{
MyContainer* c = new MyContainer();
MyObject* o1 = new MyObject();
c.add(o1);
return c;
}
返回的容器拥有其对象,并在完成后负责取消分配这些对象。在C ++中,在上面的函数退出后,访问容器对象就可以了。
使用Swig将上述类暴露给python将需要一个接口文件。此接口文件如下所示
%module freemenot
%{ #include "freemenot.h" %}
%include "std_string.i"
//Expose to Python
%include "freemenot.h"
为了使用CMake生成Python模块,使用了以下CMake脚本。
cmake_minimum_required(VERSION 2.8)
project(freemenot)
find_package(SWIG REQUIRED)
include(UseSWIG)
find_package(PythonInterp)
find_package(PythonLibs)
get_filename_component(PYTHON_LIB_FOLDER ${PYTHON_LIBRARIES} DIRECTORY CACHE)
message("Python lib folder: " ${PYTHON_LIB_FOLDER})
message("Python include folder: " ${PYTHON_INCLUDE_DIRS})
message("Python libraries: " ${PYTHON_LIBRARIES})
set(PyModule "freemenot")
include_directories(
${PYTHON_INCLUDE_PATH}
${CMAKE_CURRENT_SOURCE_DIR}
)
link_directories( ${PYTHON_LIB_FOLDER})
set(CMAKE_MODULE_LINKER_FLAGS ${CMAKE_CURRENT_SOURCE_DIR}/${PyModule}.def)
set_source_files_properties(${PyModule}.i PROPERTIES CPLUSPLUS ON)
set_source_files_properties(${PyModule}.i PROPERTIES SWIG_FLAGS "-threads")
SWIG_ADD_LIBRARY(${PyModule}
MODULE LANGUAGE python
SOURCES ${PyModule}.i freemenot.cpp)
SWIG_LINK_LIBRARIES (${PyModule} ${PYTHON_LIB_FOLDER}/Python37_CG.lib )
# INSTALL PYTHON BINDINGS
# Get the python site packages directory by invoking python
execute_process(COMMAND python -c "import site; print(site.getsitepackages()[0])" OUTPUT_VARIABLE PYTHON_SITE_PACKAGES OUTPUT_STRIP_TRAILING_WHITESPACE)
message("PYTHON_SITE_PACKAGES = ${PYTHON_SITE_PACKAGES}")
install(
TARGETS _${PyModule}
DESTINATION ${PYTHON_SITE_PACKAGES})
install(
FILES ${CMAKE_CURRENT_BINARY_DIR}/${PyModule}.py
DESTINATION ${PYTHON_SITE_PACKAGES}
)
使用CMake生成make文件,并使用borlands bcc32编译器进行编译,生成Python模块( freemenot )并将其安装到python3有效的sitepackages文件夹中。
然后,在Python中,可以使用以下脚本来阐明问题
import freemenot as fmn
def getContainer():
c = fmn.MyContainer()
o1 = fmn.MyObject("This is a label")
o1.thisown = 0
c.addObject(o1)
return c
c = getContainer()
print (c.getNrOfObjects())
#if the thisown flag for objects in the getContainer function
#is equal to 1, the following call return an undefined object
#If the flag is equal to 0, the following call will return a valid object
a = c.getObject(0)
print (a.getLabel())
这个Python代码可能看起来很好,但不能按预期工作。问题是,当函数getContainer()返回时,对象o1的内存被释放,如果 thisown 标志未设置为零。使用返回的容器访问该行之后的对象将最终导致灾难。请注意,这本身没有任何问题,因为这是pythons垃圾收集的工作原理。
对于上面的用例,可以在addObject函数中设置python对象 thisown 标记 ,这样就可以渲染Python中可用的C ++对象。 让用户设置此标志不是一个好的解决方案。 也可以使用“addObject”函数扩展python类,并在此函数中修改thisown标志,从而将这个内存技巧隐藏起来。
问题是,如何在没有扩展课程的情况下让Swig这样做? 我正在寻找使用 typemap ,或者%pythoncode ,但我似乎无法找到一个好的工作示例。
上面的代码将被一个调用Python解释器的C ++程序使用并传递给它。 C ++程序负责管理python函数中分配的内存,即使在PyFinalize()之后也是如此。
上述代码可以从github https://github.com/TotteKarlsson/miniprojects
下载