Кто-нибудь может объяснить, почему это расширение приводит к сбою Python?
Я уже много часов схожу с ума по этому поводу и не могу объяснить.
Я упростил свой код, чтобы он отображал только те строки, которые необходимы для воспроизведения сбоя:
У меня есть очень простой класс C++ в «test_class.h», который использует пару типов opencv cv::Mat и cv::KeyPoint:
class TestClass
{
public:
TestClass();
cv::Mat& get_current_frame_descriptors();
std::vector<cv::KeyPoint> _current_frame_points;
cv::Mat _current_frame_descriptors;
};
"test_class.cpp"
TestClass::TestClass()
{
}
Mat& TestClass::get_current_frame_descriptors()
{
return _current_frame_descriptors;
}
Затем у меня есть обертка cython в «test_class.pyx»:
from libcpp.vector cimport vector
cdef extern from "opencv2/core/core.hpp" namespace "cv":
cdef cppclass Mat:
Mat()
int dims, rows, cols, flags
cdef extern from "test_class.h":
cdef cppclass TClass "TestClass":
TClass()
Mat _current_frame_descriptors
Mat& get_current_frame_descriptors()
cdef class TestClass:
cdef TClass *TClass_ptr
def __cinit__(self):
self.TClass_ptr = new TClass()
def get_descriptors1(self):
m = self.TClass_ptr.get_current_frame_descriptors()
print m.dims
print m.rows
print m.cols
print m.flags
def get_descriptors2(self):
m = self.TClass_ptr._current_frame_descriptors
print m.dims
print m.rows
print m.cols
print m.flags
Обратите внимание, что TClass не объявляет _current_frame_points (вектор KeyPoints), так как нет необходимости воспроизводить сбой.
Я создаю расширение cython и тестирую его:
>>>import test_class
>>>m = test_class.TestClass()
Opencv Mat _current_frame_descriptors пуст, поэтому размеры, строки и столбцы равны нулю:
>>>m.get_descriptors1()
0
0
0
1124007936
>>>m.get_descriptors2()
Это крашит питон!!!
Теперь, если я отменю объявление других _current_frame_descriptors и _current_frame_points в test_class.h, тогда я не получу никакого сбоя!!!!
class TestClass
{
public:
TestClass();
cv::Mat& get_current_frame_descriptors();
cv::Mat _current_frame_descriptors;
std::vector<cv::KeyPoint> _current_frame_points;
};
Теперь я пересобираю C++ (я создаю его как библиотеку, на которую затем ссылаюсь с расширением cython). Я перестраиваю расширение cython и тестирую его.
>>>import test_class
>>>m = test_class.TestClass()
Opencv Mat _current_frame_descriptors пуст, поэтому, когда я это делаю
>>>m.get_descriptors1()
0
0
0
1124007936
>>>m.get_descriptors2()
0
0
0
1124007936
Теперь я получаю правильный результат!!!
Как это возможно? это ошибка цитона? ошибка opencv? или ошибка С++? или я что-то не так делаю? Мой компилятор Visual Studio Express 2009
_current_frame_points
в объявлении класса cython. AFAIK cython не будет читать определение из файла, что означает, что он не знает членов класса C++, которых нет в файле cython. Следовательно, при выполненииself.TClass_ptr._current_frame_descriptors
он обращается к неправильному месту в памяти. Замена объявлений решает проблему, потому что в этом случае cython использует правильное местоположение. Этого не должно произойти, если вы добавите_current_frame_points
в объявление Cython, так как в этот момент он сможет получить правильное место в памяти. - person Bakuriu   schedule 27.09.2013