0

I am having problems passing back an <std::vector <std::vector <boost::shared_ptr Detection>>> and I was hoping someone could help me out. I am able to pass the vector of vector but when I try and access the Detection, I get a TypeError that there is no python class registered for C++ class boost::shared_ptr which is in the Module definition.

My C++ code is as follows:

class Detection {
public: 
    Detection () {};
    ~Detection() {};
    
    double getR () {return r_;};
    double getA () {return a_;};

    double r_;
    double a_;
}

class Detector {
public
    std::vector <std::vector <boost::shared_ptr <Detection> > > getDetections();
}

std::vector <std::vector <boost::shared_ptr <Detection> > > 
Detector::getDetections () {

    std::vector <std::vector <boost::shared_ptr <Detection> > > allVecDetections;

    // Build 4 vectors containing 2 detections each
    for (unsigned int i=0; i < 4; i++) {
        std::vector<boost::shared_ptr<Detection> > vecDetections;
        for (unsigned int j = 0; j < 2; j++ ) {
            boost::shared_ptr<Detection> dt (new Detection (j+i, ts));
            dt->r_ = (j+i) + (j*i);
            dt->a_ = (j+i) * (j*i);
            vecDetections.push_back (dt);
        }
        allVecDetections.push_back (vecDetections);
    }
    return allVecDetections;
}
// Module.cpp
BOOST_PYTHON_MODULE (myModule) {
  
   boost::python::class_<Detector>("Detector")
      .def("getDetections",  &getDetections)
    ;

    boost::python::class_<Detection>("Detection")
      .def("getA",  &getA)
      .def("getR",   &getR)
     ;
  
    // Map list of Detections 
    boost::python::class_<std::vector <boost::shared_ptr <Detection> > > ("DetectionVector")
        .def(vector_indexing_suite<std::vector <boost::shared_ptr <Detection> > > ());

    // Map list of lists of Detections 
    boost::python::class_<std::vector <std::vector <boost::shared_ptr <Detection> > > > ("DetectionVectorVector")
        .def(vector_indexing_suite<std::vector<std::vector <boost::shared_ptr <Detection> > > > ());

    // Register our shared pointers with Python
    register_ptr_to_python<boost::shared_ptr<Detection> >(); 
  
}

I am able to call the getDetections from Python and get back 4 vectors with each one containing 2 Detections. Here is the Python code:

import myModule
...
plots = det.getDetections()
numvectors = len(plots)
print (f'Received {numvectors} vectors ')
jdx = 0
pdx = 0
while jdx < numvectors:
    detections = plots[jdx]
    pdx = 0
    numPlots = len(detections)
    print (f'Received {numPlots} extractions')
    while pdx < numPlots:
        print ("Extraction " + str (pdx) + ":")
        detect = detections[jdx]

This runs but I get the following output:

Received 4 vectors  
Received 2 extractions  
Extraction 0:  
Traceback (most recent call last):  
  File "scripts/test.py", line 87, in <module>
    foo = detections[jdx].getA()  
TypeError: No Python class registered for C++ class boost::shared_ptr<Detection>  

So, why am I getting complaints about Python having no registered class for boost::shared_ptr?

Thanks for any help you can give me. (The above code has been trimmed so typos may have been introduced during the writing of the question).

Taking Valeca's suggestion, I re did the work with passing back a vector<vector> (eliminating the boost::shared_ptr). Now something is unhappy with the module as I seg fault when importing the module in the Pyhton script.

Here are the new changes:

class Detection {
public: 
    Detection () {};
    ~Detection() {};

    Detection (const Detection &D) {
      : r_ (D.r_),
        a_ (D.a_)
    {};

    void operator = (const Detection &D) {
        r_ = D.r_;
        a_ = D.a_;
    };

    double getR () {return r_;};
    double getA () {return a_;};

    double r_;
    double a_;

    friend bool operator== (const Detection &d1, const Detection &d2);
    friend bool operator!= (const Detection &d1, const Detection &d2);
};

bool operator== (const Detection &d1, const Detection &d2) {
    return (d1.r_ == d2.r_ && d1.a_ == d2.a_);
}

bool operator!= (const Detection &d1, const Detection &d2) {
    return !(d1.r_ == d2.r_ && d1.a_ == d2.a_ );
}

class Detector {
public
    std::vector <std::vector <Detection> > getDetections();
}

std::vector <std::vector <Detection> > 
Detector::getDetections () {

    std::vector <std::vector <Detection> > allVecDetections;

    // Build 4 vectors containing 2 detections each
    for (unsigned int i=0; i < 4; i++) {
        std::vector<Detection> vecDetections;
        for (unsigned int j = 0; j < 2; j++ ) {
            Detection dt (j+i, ts);
            dt.r_ = (j+i) + (j*i);
            dt.a_ = (j+i) * (j*i);
            vecDetections.push_back (dt);
        }
        allVecDetections.push_back (vecDetections);
    }
    return allVecDetections;
}

// Module.cpp
BOOST_PYTHON_MODULE (myModule) {

   boost::python::class_<Detector>("Detector")
      .def("getDetections",  &getDetections)
    ;

    boost::python::class_<Detection>("Detection")
      .def("getA",  &getA)
      .def("getR",   &getR)
     ;

    // Map list of Detections 
    boost::python::class_<std::vector <Detection> > ("DetectionVector")
        .def(vector_indexing_suite<std::vector <Detection> > ());

    // Map list of lists of Detections 
    boost::python::class_<std::vector <std::vector<Detection> > > ("DetectionVectorVector")
        .def(vector_indexing_suite<std::vector<std::vector <Detection> > > ());

    // Register our shared pointers with Python
    // register_ptr_to_python<boost::shared_ptr<Detection> >(); 

}

And now the Python side seg faults on start up. I may have added more overloaded operators than needed but without them, I would see:

*/usr/include/c++/7/bits/predefined_ops.h:241:17: error: no match for ‘operator==’ (operand types are ‘Detection’ and ‘const Detection’) { return __it == _M_value; }

when compiling my module.

Thanks for any light you can shed on this.

4
  • I don’t see the reason for using shared pointers. Could you explain why you use them? Did you try to define the vector as std::vector<Detection> vecDetections and pushing back objects? Using vector as items for vector itself better be avoided. Commented Mar 19, 2021 at 14:52
  • Per your suggestion, I also tried it vector<vector<Detection>> which also then required the implementation of the ==, != = operators on the Detection class (complaints at compile time in Module.cpp without it). When I run now, I seg fault before loading the module which generally means that Python doesn't know how to instantiate my vector. So I must be missing some required overloaded methods in order for Python to know what to do upon receipt. That was one of the reasons I started using the shared_ptr to begin with. Commented Mar 21, 2021 at 17:54
  • There was in some way similar question to what you initially faced using shared_ptr stackoverflow.com/questions/5055443/…. Commented Mar 21, 2021 at 20:39
  • I suppose it is. I am able to pass back objects from C++ to Python using boost::shared_ptr and have it work as expected. I am also able to pass back a vector<vector<int>>> and have that work as expected. I'm not sure why the boost::shared_ptr or the Detection class is having issues - the only thing I can think of is that I am missing a kep mapping in the module definition. Commented Mar 21, 2021 at 20:53

1 Answer 1

0

I got it working with vector< vector <boost::shared_ptr > > It turns out I was missing the NoProxy override when I registered my vector. See fixed code in Module.cpp.

    boost::python::class_<std::vector <boost::shared_ptr <Detection> > > ("DetectionVector")
        .def(vector_indexing_suite<std::vector <boost::shared_ptr <Detection> >,true > ());

    // Map list of lists of Detections 
    boost::python::class_<std::vector <std::vector <boost::shared_ptr <Detection> > > > ("DetectionVectorVector")
        .def(vector_indexing_suite<std::vector<std::vector <boost::shared_ptr <Detection> > >, true > ());


I remember seeing a Stack Overflow message about this in which the author said that the true really matters. It really does. Thanks to all who helped with suggestions.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.