Pointing to variables already defined in a C++ struct

100 views
Skip to first unread message

CyclingNinja

unread,
Oct 21, 2016, 12:43:02 PM10/21/16
to cython-users

I'm trying to get a simple example working pointing at a couple of integers atm but will eventually be std::vector

this is what I currently have

struct_ex.h

namespace examp {
  struct _OutVectors {
    int x;
    int y;
} OutVectors;
}


struct_ex.cpp (not convinced this is right)


#include <stdlib.h>
#include "struct_ex.h"

namespace examp{
  struct OutVectors s1;
  s1-> 1
  s1-> 2
}


then my pyx

cdef extern from "struct_ex.h" namespace "examp":
    cdef cppclass OutVectors:
        pass
       
cdef class PyClass:
    cdef OutVectors *retval

    @staticmethod
    cdef create(OutVectors *retval)
        cdef PyClass pc = PyClass()
        pc.retval = retval
        return retval


I've been going round in circles, thats what i have currently. I feel like I've seen all the errors, I need help understanding what is going on with the pointers.

Please, I need help, thank you in advance.

Björn Dahlgren

unread,
Oct 21, 2016, 2:28:42 PM10/21/16
to cython-users


On Friday, 21 October 2016 18:43:02 UTC+2, CyclingNinja wrote:

I'm trying to get a simple example working pointing at a couple of integers atm but will eventually be std::vector

We've all been there, you'll get the hang of it.
Your .cpp would need a factory function for your code to make sense. But in C++ that is usually done by constructors.
I created a small self contained example based on your files:

https://gist.github.com/bjodah/001633712d2531f20a74ab975bb08e62

(in this example a constructor does not make any sense, but I added it so that you can see the syntax)

To cython-devs: using Cython master does not work for this example (I get ImportError: Building module my failed: ['DistutilsArgError: option --pyrex-c-in-temp not recognized\n'])

Samuel M Bennett

unread,
Oct 24, 2016, 7:47:06 AM10/24/16
to cython...@googlegroups.com
Thanks man I really appreciate this,

If you don't mind I have a few clarification questions.

What is the role of the Pyd file? I've built simple examples before, such as this https://gist.github.com/CyclingNinja/9e8477277d14272785371324c8ab9a38 where I've had issues getting it working till I put the contents of the Pyd file into the top of the pyx file.

Also, I've not seen the my.pybld file before, is it just a straight swap for setup.py or is it more robust?

Also, also, is defining a vector as simple as `aname(x, y)` and is all the pratting around with std::vector not needed?

I presume i can use __callcoc__ to pass out a calculated vector?

Sorry If i've entirely missed the point.

Thank you for your patience,






--

---
You received this message because you are subscribed to the Google Groups "cython-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to cython-users+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Björn Dahlgren

unread,
Oct 24, 2016, 12:30:28 PM10/24/16
to cython-users


On Monday, 24 October 2016 13:47:06 UTC+2, CyclingNinja wrote:
If you don't mind I have a few clarification questions.
Not at all
 

What is the role of the Pyd file? I've built simple examples before, such as this https://gist.github.com/CyclingNinja/9e8477277d14272785371324c8ab9a38 where I've had issues getting it working till I put the contents of the Pyd file into the top of the pyx file.

So the pxd file is not strictly necessary, if you will only reference things in the C++ library from one single .pyx file you may just as well put the definitions in the pyx file.
The pxd file is mostly there to allow sharing of the definitions. However, another bonus is that handling name clashes is quite elegant using e.g. "from mycpplib cimport yield as cpp_yield".
 

Also, I've not seen the my.pybld file before, is it just a straight swap for setup.py or is it more robust?

It is my impression that it is actually less robust (it is used by pyximport which I believe don't see as much testing).
I would recommend a setup.py file for your project. But it can be convenient if you want your .pyx file to be compiled automatically.
 

Also, also, is defining a vector as simple as `aname(x, y)` and is all the pratting around with std::vector not needed?

Not quite sure what you mean here.
Do you want to OutVectors to contain one vector for x, and one vector for y?
Or do you want OutVectors to contain one vector of x,y pairs?
 

I presume i can use __callcoc__ to pass out a calculated vector?

If your results are to be available to Python I would recommend allocating in Python using e.g. numpy.array
and then pass a pointer to the data to the C++ library (if possible).

If you allocate data for you objects using malloc/calloc or 'new' in C++ you have to be careful to delete the data
when, and only when no python objects references the data any longer.

Samuel M Bennett

unread,
Oct 26, 2016, 12:56:42 AM10/26/16
to cython...@googlegroups.com
NB: I got it working in the end by removing the 1.0 from the vector copy so it now looks like:

OutVectors(std::vector<double> A_={}, std::vector<double> B_={}) : A(A_), B(B_) {}

please let me know if this is a horrible, terrible idea.

On 25 October 2016 at 10:16, Samuel M Bennett <s.m.b...@sheffield.ac.uk> wrote:
Thanks man, that’s all really good.

As for the vector clarification.

I'll looking to read out several separate vectors. I'm currently working with and adapting your code. At the moment, I'm trying to initialise vectors of length 1 and then expand them like this

.pyx
cdef class PyStruct:
    cdef OutVectors *thisptr  # hold a c++ instance of the structure

    def __cinit__(self, vector[double] A={1.0}, vector[double] B={1.0}):
        self.thisptr = new OutVectors(A, B)

    def __dealloc__(self):
        del self.thisptr

    def RetVals(self):
        s = PySquare()
        for i in range(10):
            print(i)
            self.thisptr.A.push_back(i)
            self.thisptr.B.push_back(s.get_sqr(i))
        return self.thisptr.A, self.thisptr.B


PySquare is a class of methods which I built up learning the basics of Cython, in this case get_sqr(x) returns x squared (shockingly enough)

and the .h

#include <vector>

namespace ops {
    struct OutVectors {
        std::vector<double> A, B;
        OutVectors(std::vector<double> A_={1.0}, std::vector<double> B_={1.0}) : A(A_), B(B_) {}
    };



However I'm getting an error of

 error: converting to ‘std::vector<double>’ from initializer list would use explicit constructor ‘std::vector<_Tp, _Alloc>::vector(std::vector<_Tp, _Alloc>::size_type, const value_type&, const allocator_type&) [with _Tp = double; _Alloc = std::allocator<double>; std::vector<_Tp, _Alloc>::size_type = long unsigned int; std::vector<_Tp, _Alloc>::value_type = double; std::vector<_Tp, _Alloc>::allocator_type = std::allocator<double>]’
squaremod.h:11:71: warning: narrowing conversion of ‘1.0e+0’ from ‘double’ to ‘std::vector<double>::size_type {aka long unsigned int}’ inside { } is ill-formed in C++11 [-Wnarrowing]


Which I think is complaining about the initialiser brackets and allocated space. I suspect I need to define the length of the vector first however I'm not sure how to do that with the bracing notation. Or what the notation is called so I can find the docs.

Hope that makes sense and isn't just garbled nonsense.


Samuel M Bennett

unread,
Oct 26, 2016, 12:56:42 AM10/26/16
to cython...@googlegroups.com

Björn Dahlgren

unread,
Oct 27, 2016, 5:26:16 PM10/27/16
to cython-users


On Wednesday, 26 October 2016 06:56:42 UTC+2, CyclingNinja wrote:
Thanks man, that’s all really good.

As for the vector clarification.

I'll looking to read out several separate vectors. I'm currently working with and adapting your code. At the moment, I'm trying to initialise vectors of length 1 and then expand them like this

Could you try to create a minimal example in pure Python that is working and is demonstrating what you are trying to achieve? (you could name things you expect to be C++ parts as CppClass etc)
It's all a bit opaque to me at the moment.

Samuel M Bennett

unread,
Oct 28, 2016, 12:07:28 PM10/28/16
to cython...@googlegroups.com
Ok, so its not just a python example its is a whole cython set of files. Using what you showed me before.

https://gist.github.com/CyclingNinja/974d43582a16ccc747e54ee038114121

however I'm getting an error on

    def get_cube(self, double x):
        return self.c_powers.getCube(x)
     
    def get_struct_vecs(self, v):
        return self.c_powers.getStuctVec(v) 
                                       ^
------------------------------------------------------------

powers_wrapper.pyx:45:40: Cannot convert 'OutVectors' to Python object


which I suspect is to do with my trying to return the structure in the C++ functions

Hope thats more clear. If this fails, I'll get a really simple python example functional.



--

Björn Dahlgren

unread,
Oct 29, 2016, 6:00:41 PM10/29/16
to cython-users

On Friday, 28 October 2016 18:07:28 UTC+2, CyclingNinja wrote:
powers_wrapper.pyx:45:40: Cannot convert 'OutVectors' to Python object

It is tricky to wrap C++ functions which return objects without nullary constructor since Cython does not support stack allocation
(I don't know enough about Cython to know why this limitations exists). Therefore it is easier wrapping functions returning pointers
(smart or not) and have a special argument in __cinit__ which assigns to thisptr when given.
See this stack overflow question for a similar example:
http://stackoverflow.com/questions/28973153/cython-how-to-wrap-a-c-function-that-returns-a-c-object

In your case we have a nullary constructor, we just need to make Cython aware of it. I've fixed your code here:
https://gist.github.com/bjodah/5e89fd002036758e9037276fbfa2bab1

Here is the output:

$ python call_wrapper.py
Squared 4.0,Cubed 8.0

Best regards,
Björn
Reply all
Reply to author
Forward
0 new messages