Overloading operators in C++

205 views
Skip to first unread message

skrat

unread,
Dec 9, 2010, 5:45:26 PM12/9/10
to cython-users
Hi, I'm trying to wrap carve library for constructive geometry,
starting with vector class, I can't get it to overload operators. I
followed all the docs, this should work:

cdef extern from "carve/geom.hpp" namespace "carve::geom":
cdef cppclass vector[T]:
double x, y, z
vector()
vector[T] operator-(vector[T])
vector[T] operator+(vector[T])


cdef extern from *:
ctypedef int n3 "3"

cdef class vector3:
cdef vector[n3] *_ptr
def __cinit__(self):
self._ptr = new vector[n3]()

def __dealloc__(self):
del self._ptr

def __add__(vector3 a, vector3 b):
r = vector3()
del r._ptr
r._ptr = a._ptr + b._ptr
return r

Robert Bradshaw

unread,
Dec 9, 2010, 5:48:34 PM12/9/10
to cython...@googlegroups.com
On Thu, Dec 9, 2010 at 2:45 PM, skrat <dusan.m...@gmail.com> wrote:
> Hi, I'm trying to wrap carve library for constructive geometry,
> starting with vector class, I can't get it to overload operators. I
> followed all the docs, this should work:

What version of Cython are you using? What error are you getting?

- Robert

skrat

unread,
Dec 10, 2010, 5:17:33 AM12/10/10
to cython-users
I'm using release 0.13, and the error is:

$ python setup.py build_ext -i
running build_ext
cythoning carve/carve.pyx to carve/carve.cpp

Error converting Pyrex file to C:
------------------------------------------------------------
...
return a.x == b.x and a.y == b.y and a.z == b.z

def __add__(vector3 a, vector3 b):
r = vector3()
del r._ptr
r._ptr = a._ptr + b._ptr
^
------------------------------------------------------------

/home/skrat/workspace/floorplanner/pycarve/carve/geom.pxi:22:24:
Invalid operand types for '+' (vector<n3> *; vector<n3> *)

My C++ skills doesn't exist, this my first contact with the language,
I suspect wrong return type in my cppclass definition, but then the
error would look differently I guess.

On Dec 9, 11:48 pm, Robert Bradshaw <rober...@math.washington.edu>
wrote:

Robert Bradshaw

unread,
Dec 10, 2010, 12:11:11 PM12/10/10
to cython...@googlegroups.com
On Fri, Dec 10, 2010 at 2:17 AM, skrat <dusan.m...@gmail.com> wrote:
> I'm using release 0.13, and the error is:
>
> $ python setup.py build_ext -i
> running build_ext
> cythoning carve/carve.pyx to carve/carve.cpp
>
> Error converting Pyrex file to C:
> ------------------------------------------------------------
> ...
>            return a.x == b.x and a.y == b.y and a.z == b.z
>
>    def __add__(vector3 a, vector3 b):
>        r = vector3()
>        del r._ptr
>        r._ptr = a._ptr + b._ptr
>                       ^
> ------------------------------------------------------------
>
> /home/skrat/workspace/floorplanner/pycarve/carve/geom.pxi:22:24:
> Invalid operand types for '+' (vector<n3> *; vector<n3> *)

a._ptr and b._prtr are pointers, and you can't add pointers. Instead,
you need to dereference them, i.e.

r._ptr[0] = a._ptr[0] + b._ptr[0]

(or use cython.operator.dereference). Yeah, it's not as pretty as it could be.

- Robert

skrat

unread,
Dec 10, 2010, 3:05:33 PM12/10/10
to cython-users
Hi Robert, perfect, that worked, I have following code, but I'm
wondering whether it's leaking memory, not sure what [0] really does
and how does it work along with del keyword. I'm also curious whether
there isn't a better way to initialize an instance using ctype
pointer. What about == operator? And lastly, is creating concrete
types (like vector3 for vector[3]) the usual approach to deal with C++
template types? Thank you

from cython.operator cimport dereference as deref

cdef extern from *:
ctypedef int n3 "3"

cdef class vector3:
cdef vector[n3] *_ptr
def __cinit__(self):
self._ptr = new vector[n3]()

def __init__(self, x=0.0, y=0.0, z=0.0):
self.x, self.y, self.z = x, y, z

def __dealloc__(self):
del self._ptr

def __richcmp__(a, b, op):
if op == 2:
return a.x == b.x and a.y == b.y and a.z == b.z

def __add__(vector3 a, vector3 b):
return vector3()._set_(deref(a._ptr) + deref(b._ptr))

cdef _set_(self, vector[n3] val):
self._ptr[0] = val
return self



On Dec 10, 6:11 pm, Robert Bradshaw <rober...@math.washington.edu>
wrote:

Robert Bradshaw

unread,
Dec 10, 2010, 3:49:08 PM12/10/10
to cython...@googlegroups.com
On Fri, Dec 10, 2010 at 12:05 PM, skrat <dusan.m...@gmail.com> wrote:
> Hi Robert, perfect, that worked, I have following code, but I'm
> wondering whether it's leaking memory,

Yes, your _set_ function doesn't deallocate self._ptr first.

> not sure what [0] really does and how does

Same as in C or C++, if ptr is a pointer, then ptr[0] is the object
being pointed to. *ptr and ptr[0] mean exactly the same thing (unless,
in C++, one or both have been overridden).

> it work along with del keyword. I'm also curious whether
> there isn't a better way to initialize an instance using ctype
> pointer.

You can set the pointer to null initially, and then set it. (Note that
this makes your API potentially unsafe.)

>What about == operator?

Same, just be sure to dereference first, or you'll be comparing
pointers not the objects they point to.

> And lastly, is creating concrete
> types (like vector3 for vector[3]) the usual approach to deal with C++
> template types? Thank you

Yes, for the moment at least. Note that even in C++ the parameters
must be resolved at compile time.

- Robert

skrat

unread,
Dec 10, 2010, 4:01:23 PM12/10/10
to cython-users
Very nice! Thank you, that explained a lot, sorry to bother you even
more, but any idea how to wrap following function? I run through all
the docs and could not figure this one:

template<unsigned ndim, typename val_t>
double dot(const vector<ndim> &a, const val_t &b) {
double r = 0.0;
for (unsigned i = 0; i < ndim; ++i) r += a[i] * b[i];
return r;
}


On Dec 10, 9:49 pm, Robert Bradshaw <rober...@math.washington.edu>
wrote:

Du?an Maliarik

unread,
Dec 10, 2010, 6:30:32 PM12/10/10
to cython...@googlegroups.com
After deallocating pointer I'm hitting 

*** glibc detected *** python: double free or corruption (fasttop): 0x0982eab0 ***

here it is:

    cdef _set_(self, vector[n3] val):
        del self._ptr

Robert Bradshaw

unread,
Dec 20, 2010, 3:21:43 PM12/20/10
to cython...@googlegroups.com
On Fri, Dec 10, 2010 at 1:01 PM, skrat <dusan.m...@gmail.com> wrote:
> Very nice! Thank you, that explained a lot, sorry to bother you even
> more, but any idea how to wrap following function? I run through all
> the docs and could not figure this one:
>
>    template<unsigned ndim, typename val_t>
>    double dot(const vector<ndim> &a, const val_t &b) {
>      double r = 0.0;
>      for (unsigned i = 0; i < ndim; ++i) r += a[i] * b[i];
>      return r;
>    }

We don't yet support templated functions, you'll have to declare this
the "old style" way.

- Robert

Robert Bradshaw

unread,
Dec 20, 2010, 3:26:44 PM12/20/10
to cython...@googlegroups.com

Sorry, you'd only need to del if you were re-assiging self._ptr.
Assigning to self._ptr[0] is just fine to do, don't deallocate first.

I still think (a variant of) your original add function was cleaner,

def __add__(vector3 a, vector3 b):
r = vector3()

r._ptr[0] = a._ptr]0] + b._ptr[0]

return r

- Robert

Reply all
Reply to author
Forward
0 new messages