0

I am attempting to return a const reference to a vector of unique ptrs from a C++ library to a python interface. I am trying code similar to the below, but I am getting compilation errors when trying to call py::bind_vector<std::vector<std::unique_ptr<A>>>

#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/stl_bind.h>

class A
{
  public:
    A( int x ){ i = x; }
    A(const A&) = delete;
    A& operator=(const A&) = delete;
    int getI() { return i; }

  private:
    int i;
};

class Test
{
  public:
    Test(){
      for(int i = 0; i < 10; ++i) {
        avec_.emplace_back( std::make_unique<A>(i));
      }
    }
    Test( const Test& ) = delete;
    Test& operator=(const Test& ) = delete;

    const std::vector<std::unique_ptr<A>>& getVec() const { return avec_; }

  private:
    std::vector<std::unique_ptr<A>> avec_;
};

PYBIND11_MODULE(UniqContainer, m) {

  py::bind_vector<std::vector<std::unique_ptr<A>>>(m, "VecA", py::module_local() );

  py::class_<A>(m, "A")
    .def( py::init<int>() )
    .def( "getI", &A::getI );

  py::class_<Test>(m, "Test" )
    .def( py::init<>() )
    .def( "getVec", &Test::getVec, py::return_value_policy::reference_internal );
}

My question is - is it possible to return a const reference to std::vector<std::unique_ptr<A>> in python bindings?

EDIT: Added:

  • copy ctor and assignment operator delete
  • py::return_value_policy::reference_internal
Rafael A.
  • 1
  • 2
  • This might help: https://stackoverflow.com/a/53807492/955273 – Steve Lorimer May 19 '20 at 16:43
  • I did try that and unfortunately it did not resolve the issue. I left it out of my example for brevity however, I should have made note.. – Rafael A. May 19 '20 at 16:56
  • Most likely what you need it setting `return_value_policy::reference_internal` as the return policy. If you have tried that and it didn't work update the question with this information such that we can help you finding out why it didn't work. – darcamo May 19 '20 at 17:46
  • Thanks for the suggestion - the compiler errors are coming from the call to `py::bind_vector` so that is not the issue. I will update my question. – Rafael A. May 19 '20 at 18:18

1 Answers1

0

So this is the best I can come up with. It might have life-span issues, if you save handles to the instances of A in python and then delete them in c++. You can't use reference_internal in the context that I'm using it because it doesn't know what lifespan is being referred to. You might be able to explicitly add py::keep_alive to the function def as well to keep things in scope. I don't know what you're lifetime requirements are and I'm still a little hazy on that part of the API.

  py::class_<Test>(m, "Test" )
    .def( py::init<>() )
    .def( "getVec",
          [](const Test& obj) {
            auto pylist = py::list();
            for (auto& ptr : obj.getVec()) {
              auto pyobj = py::cast(*ptr, py::return_value_policy::reference);
              pylist.append(pyobj);
            }
            return pylist;
          });
}

Basically, have to manually create the py::list and then cast the smart pointers in it to py::object by reference to populate the list.

(note, I also removed the py::bind_vector to make everything compile)

Jesse C
  • 779
  • 4
  • 11