我有一个结构体,看起来像这样:
foo:
struct A {
string a;
string b;
};
它在.pyx文件中有匹配的定义,以及python包装器:
lib_foo.pyx:
cdef extern from "foo.h":
cdef struct A:
string a
string b
cdef class PyA:
cdef A* thisptr
def __cinit__(self):
self.thisptr = <A*>malloc(sizeof(A))
cdef A* getThis(self):
return self.thisptr
def bar(self):
self.thisptr.a = "Hello" # works fine!
def bar2(self):
return self.thisptr.a # this too!
def bar(PyA f):
f.getThis().a = "Hello"
def bar2(PyA a):
return f.getThis().a
这个构建没有任何问题,我得到一个libfoo。我在一个简单的测试脚本中使用它:
import libfoo
f = libfoo.PyA()
#f.bar() no problems
libfoo.bar(f) # this line and the next have unpredictable behavior!
print libfoo.bar2(f)
在重复运行时,有时会成功打印"Hello",有时会出现段错误。更奇怪的是,两个函数bar和bar2作为类PyA的成员函数似乎工作得很好。我做了一堆python包装,使用这样的getThis()函数来提供指向类和结构体的指针,直到现在才出现问题。是字符串引起的问题吗?
py编辑:
from distutils.core import setup
import distutils.util as du
from distutils.extension import Extension
from Cython.Distutils import build_ext
import os
os.environ["CC"] = "/app/gcc/4.8.2/bin/g++"
os.environ["CXX"] = "/app/gcc/4.8.2/bin/g++"
os.environ["CPP"] = "/app/gcc/4.8.2/bin/g++"
os.environ["CMAKE_CXX_COMPILER"] = "/app/gcc/4.8.2/bin/g++"
ext_modules = [
Extension(
name = "libfoo",
sources = ["lib_foo.pyx"],
include_dirs = ["/usr/local/include", "/usr/include"],
library_dirs = ["/usr/local/lib", "/usr/lib"],
language = "c++",
)]
setup(
name = "libfoo",
cmdclass = {"build_ext" : build_ext},
ext_modules = ext_modules
)
首先,您必须告诉Cython struct A
具有c++类语义(cdef cppclass
),而不是C结构语义(cdef struct
),因为它具有非平凡的构造函数,因为嵌入了字符串。
from libcpp.string cimport string
cdef extern from "foo.h":
cdef cppclass A:
string a
string b
然后使用操作符new
分配,而不是malloc,就像您在c++中所做的那样。
def __cinit__(self):
self.thisptr = new A()
绕过构造函数并使用未初始化的实例是导致崩溃的原因。
当Python包装器被丢弃时,不要忘记删除这个对象:
def __dealloc__(self):
del self.thisptr
此外,提供明确的方法来确定地释放c级资源(独立于Python GC)也是一个好主意:
def dispose(self): # or "close" or whatever
del self.thisptr
self.thisptr = NULL