Cython与结构的字符串成员函数表现奇怪

时间:2014-06-13 14:37:56

标签: python c++ struct cython

我有一个看起来像这样的结构:

foo.h中:

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.so,我在一个简单的测试脚本中使用:

import libfoo
f = libfoo.PyA()
#f.bar() no problems
libfoo.bar(f) # this line and the next have unpredictable behavior!
print libfoo.bar2(f)

在重复运行中,有时会成功打印&#34; Hello&#34;,有时会打印出段错误。更奇怪的是,两个函数bar和bar2似乎可以作为PyA类的成员函数正常工作。我做了一堆cython包装,只使用这样的getThis()函数来提供指向类和结构的指针,直到现在才出现问题。它可能是导致问题的字符串吗?

编辑:setup.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
    )

1 个答案:

答案 0 :(得分:1)

首先,您必须告诉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()

绕过构造函数并使用uninitializes实例是崩溃的原因。

在处理Python包装器时,不要忘记删除此对象:

def __dealloc__(self):
    del self.thisptr

此外,提供确定性释放C级资源的显式方法(独立于Python GC)是个好主意:

def dispose(self):  # or "close" or whatever
    del self.thisptr
    self.thisptr = NULL