添加swig pythoncode在Python对象上设置thisown标志

时间:2018-05-09 17:39:17

标签: python c++ swig

我有一个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

下载

0 个答案:

没有答案