10

How to create a numpy array from C++ side and give that to python?

I want Python to do the clean up when the returned array is no longer used by Python.

C++ side would not use delete ret; to free the memory allocated by new double[size];.

Is the following correct?

#include "pybind11/pybind11.h"
#include "pybind11/numpy.h"

namespace py = pybind11;

py::array_t<double> make_array(const py::ssize_t size) {
    double* ret = new double[size];
    return py::array(size, ret);
}

PYBIND11_MODULE(my_module, m) {
    .def("make_array", &make_array,
         py::return_value_policy::take_ownership);
}
R zu
  • 2,034
  • 12
  • 30
  • I have to use the numpy instead of eigen interface of pybind11 because I use a structured numpy array. – R zu Mar 08 '18 at 18:25

1 Answers1

16

Your are quite correct. A little better solution is below.

#include "pybind11/pybind11.h"
#include "pybind11/numpy.h"

namespace py = pybind11;

py::array_t<double> make_array(const py::ssize_t size) {
    // No pointer is passed, so NumPy will allocate the buffer
    return py::array_t<double>(size);
}

PYBIND11_MODULE(my_module, m) {
    .def("make_array", &make_array,
         py::return_value_policy::move); // Return policy can be left default, i.e. return_value_policy::automatic
}
273K
  • 29,503
  • 10
  • 41
  • 64
  • hmm. And this won't make a copy? I am checking if `py::array_t` has a move constructor.... It seems to have one here: https://github.com/pybind/pybind11/blob/13c08072dc98ba679251ab8b17cf7e959d924fea/include/pybind11/numpy.h#L814 – R zu Mar 08 '18 at 18:10
  • 1
    Sure it will not make a copy due to return value optimization and copy elision. – 273K Mar 08 '18 at 18:14
  • The casting for `py::return_value_policy::move` is here: https://github.com/pybind/pybind11/blob/13c08072dc98ba679251ab8b17cf7e959d924fea/include/pybind11/cast.h#L541 Thanks. – R zu Mar 08 '18 at 18:17
  • 2
    Really really wish they talk about this in the official documentation... – R zu Mar 08 '18 at 18:20
  • Does `py::array_t` initialize the newly allocated buffer? Or should we initialize it ourselves? – John Nov 25 '20 at 11:39