I'm working on a Python project where I'd like to interface with a C++ package that has already been written. Since I'll be using Cython in other portions of this project, I'd prefer to wrap using Cython.
In brief, I need to wrap a function, FooBar, that returns an object of custom class type Bar.
Here's the Bar.h:
#include <cstddef> // For size_t
#include <vector>
/* data returned by function FooBar()*/
class Bar {
public:
size_t X;
std::vector<size_t> Y;
std::vector<double> Z;
std::vector<double> M;
std::vector<size_t> N;
};
Bar FooBar(const std::vector<double> & O, size_t P, size_t Q);
And PyBar.pyx:
from libcpp.vector cimport vector
cdef extern from "Bar.h":
cdef cppclass Bar:
size_t X
vector[size_t] Y
vector[double] Z
vector[double] M
vector[size_t] N
cdef Bar FooBar(const vector[double] & O, size_t P, size_t Q)
cdef class PyBar:
cdef Bar *thisptr # hold a C++ instance which we're wrapping
def __cinit__(self, O, P, Q):
C_Bar = FooBar(O, P, Q)
self.thisptr = &C_Bar
def __dealloc__(self):
del self.thisptr
Actual Question: Is this even the right approach to what I want to do? For reference, if I just tried to wrap the class by itself I have had no problem: I can import the module, create objects using PyBar(), and underlying C methods implemented on the class would work. The issue is trying to wrap a function that returns objects of the C++ class. In the wild, I'll never actually want to create PyBar representation of any Bar object that wasn't created by FooBar, so this is the approach I decided upon after much head scratching.
With respect to the first part of the problem, I think the more elegant change would be to have FooBar defined as:
Bar* FooBar(const std::vector<double> & O, size_t P, size_t Q);
and have it return a "new" allocated pointer. I think in your original Cython code __cinit__
you'll create a stack allocated Bar, take a pointer of that, and then that will expire resulting in eventual disaster.
An alternative solution that might work would be be to keep FooBar returning Bar, change PyBar so it starts
cdef class PyBar:
cdef Bar this_obj
def __cinit__(self, O, P, Q):
self.this_obj = FooBar(O,P,Q)
i.e. keeps an object rather than a pointer. No __dealloc__
should be necessary.
I don't know about the undefined symbol error...
Collected from the Internet
Please contact [email protected] to delete if infringement.
Comments