-
Hello, I hope someone can help me out with the following problem(s). I would like to wrap a code to Python which I tried to simplify as much as possible to derive a minimal example. There are two classes. The #include <pybind11/pybind11.h>
namespace py = pybind11;
class Child{
public:
std::string helloChild(){
return "Hi there";
}
};
class Parent{
public:
// Problem 1:
const std::unique_ptr<Child>& get_Child(){
m_Child = std::make_unique<Child>();
return m_Child;
};
// Problem 2:
const std::vector<std::unique_ptr<Child>>& get_Childs(){
m_Childs.push_back(std::make_unique<Child>());
return m_Childs;
};
private:
std::vector<std::unique_ptr<Child>> m_Childs;
std::unique_ptr<Child> m_Child;
}; In C++ I would call the classes like so: Parent* m_Parent = new Parent();
const std::unique_ptr<Child>& Child = m_Parent->get_Child();
std::cout << Child->helloChild() << std::endl;
delete m_Parent; Looking at the first problem, I would approach the Pybind11 wrapper like below: PYBIND11_MODULE(exampleLib,m){
// Solution for problem 1:
py::class_<Child>(m, "Child")
.def("helloChild", &Child::helloChild);
py::class_<Parent>(m,"Parent")
.def(py::init<>())
.def("get_Child", &Parent::get_Child);
} This returns a
Could you please suggest how to handle the first problem? Is there a way to convert into a raw pointer when using Python (maybe not the best idea, but as a worst-case workaround). Or some further reading material on this problem? Thanks! |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 1 reply
-
In addition: I just found out that the following solution would work. Would you recommend this approach or suggest an alternative treatment of the unique_ptr in Problem 1? PYBIND11_MODULE(exampleLib,m){
// Solution for problem 1:
py::class_<Child>(m, "Child")
.def(py::init<>())
.def("helloChild", &Child::helloChild);
py::class_<Parent>(m,"Parent")
.def(py::init<>())
.def("get_Child", [](Parent* parent){return parent->get_Child().get(); });
} |
Beta Was this translation helpful? Give feedback.
-
@MarAlder I extended your code a little bit. Most important thing is to notice how vector is moved -- please look it up why vectors of unique pointers are movable but not copyable. Moreover you need to create new Child before moving it inside the vector itself. "Temporary" unique pointer cannot be passed inside Second important change are return policies added to Parent's bindings, these are critical since omitting them is resulting in memory deallocation errors (refer to pybind docs here). Here is the sample: #include <vector>
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
namespace py = pybind11;
class Child{
public:
Child(int num) : _num(num) {}
std::string helloChild(){
return "Hi there Child" + std::to_string(_num);
}
int _num;
};
class Parent{
public:
// Problem 1:
const std::unique_ptr<Child>& get_Child(){
m_Child = std::make_unique<Child>(6);
return m_Child;
};
// Problem 2:
std::vector<std::unique_ptr<Child>>&& get_Childs(){
auto some_child = std::make_unique<Child>(1);
m_Childs.push_back(std::move(some_child));
auto other_child = std::make_unique<Child>(2);
m_Childs.push_back(std::move(other_child));
return std::move(m_Childs);
};
private:
std::unique_ptr<Child> m_Child;
std::vector<std::unique_ptr<Child>> m_Childs;
};
namespace py = pybind11;
PYBIND11_MODULE(mymodule, m)
{
py::class_<Child>(m, "Child")
.def(py::init<int>())
.def("hello", &Child::helloChild)
.def("__repr__", [](const Child* self) {
return "Child" + std::to_string(self->_num);
});
py::class_<Parent>(m, "Parent")
.def(py::init<>())
.def("get_child", [](Parent* parent) {
return parent->get_Child().get();
}, py::return_value_policy::reference) // important policy!
.def("get_children", [](Parent* parent) {
return parent->get_Childs();
}, py::return_value_policy::reference_internal); // important policy!
} And a little test of the bindings: In [1]: import mymodule as m
...: p = m.Parent()
...: c = p.get_child()
...: print(c.hello())
Hi there Child6
In [2]: arr = p.get_children()
...: print(arr)
...: print(arr[0].hello())
[Child1, Child2]
Hi there Child1
In [3]: arr[0] = c
...: print(arr)
...: print(arr[0].hello())
[Child6, Child2]
Hi there Child6 Hope this helps! 🚀 |
Beta Was this translation helpful? Give feedback.
@MarAlder I extended your code a little bit.
Most important thing is to notice how vector is moved -- please look it up why vectors of unique pointers are movable but not copyable. Moreover you need to create new Child before moving it inside the vector itself. "Temporary" unique pointer cannot be passed inside
push_back
.Second important change are return policies added to Parent's bindings, these are critical since omitting them is resulting in memory deallocation errors (refer to pybind docs here).
Here is the sample: