2014-06-13 3 views
1

구조체의 문자열 멤버 함수와 이상한 행동 :사이 썬 I는 다음과 같습니다 구조체를 가지고

foo.h :

struct A { 
    string a; 
    string b; 
}; 

이 같은 .pyx 파일에 일치하는 정의가

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) 

이상 반복 실행을, 때로는이 성공적으로 "안녕하세요"인쇄되며, 다른 시간 세그먼트 폴트. 더 낯선 사람, bar와 bar2의 두 함수는 PyA 클래스의 멤버 함수처럼 잘 작동하는 것 같습니다. 클래스와 구조체에 대한 포인터를 제공하기 위해 getThis() 함수를 사용하여 많은 양의 cython을 래핑했습니다. 지금까지는 문제가 없었습니다. 문제의 원인이되는 문자열 일 수 있습니까?

편집 : 그것은 사소 생성자를 가지고 있기 때문에 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 
    ) 
+0

우리는 완벽하고 실행 가능한 예를 사용할 수 있습니까? 현재 컴파일되지 않습니다. – Veedrac

+0

괜찮아요. 편집에 내 setup.py를 포함 시켰습니다. 그러나 그것은 잘 컴파일되어야합니다. 어떤 종류의 컴파일 오류가 발생합니까? – Ben

답변

1

첫째, 당신으로 인해 포함 된 문자열을, 아니 C 구조체의 의미 (cdef struct) struct A이 (cdef cppclass)를 C++ 클래스의 의미를 가지고 사이 썬 말할 필요 .

from libcpp.string cimport string 

cdef extern from "foo.h": 
    cdef cppclass A: 
     string a 
     string b 

은 그럼 당신은 C++에서하는 것과 동일하게, 운영자 new,하지의 malloc으로 할당합니다.

def __cinit__(self): 
    self.thisptr = new A() 

생성자를 무시하고 초기화되지 않은 인스턴스를 사용하면 충돌이 발생합니다.

파이썬 래퍼가 배치 될 때이 개체를 삭제하는 것을 잊지 마세요 :

def __dealloc__(self): 
    del self.thisptr 

또한,이 결정 론적으로 (파이썬 GC의 독립적 인) C 레벨 리소스를 해제하기위한 명시적인 방법을 제공하는 것이 좋습니다 :

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

불행히도 저는 C++ 소스를 변경할 수 없습니다. 구조체가 아닌 클래스를 래핑하는이 메서드를 사용했습니다. 구조체와 비슷한 기능이 있기를 바랬습니다. – Ben

+0

C++ 소스와 아무 관련이 없습니다. 'struct A'는'cdef struct' 대신에'cdef cppclass'를 사용하여 C++ 의미론을 가지고 있다는 것을 _Cython_에게 알릴 필요가 있습니다. C++에서이를 선언하는 데 사용되는 실제 키워드는 부적합합니다. –

+0

우와, 그랬어. 구조체와 클래스는 분명히 다른 것들입니다. 어떻게 cython이 그것들을 같은 것으로 해석 할 수 있습니까? 그 클래스는 구조체와 같지만 OOP 의미에서옵니다. 어쨌든, 현상금을 즐기십시오 :) – Ben