У меня есть функция C ++, которая возвращает std::vector
, и, используя Pybind11, я хотел бы вернуть содержимое этого вектора в виде массива Numpy без необходимости копировать базовые данные вектора в массив необработанных данных.
Текущая попытка
В этот хорошо написанный SO-ответ автор демонстрирует, как гарантировать, что массив необработанных данных, созданный в C ++, соответствующим образом освобождается, когдамассив Numpy имеет нулевое количество ссылок.Я попытался написать версию этого, используя std::vector
вместо этого:
// aside - I made a templated version of the wrapper with which
// I create specific instances of in the PYBIND11_MODULE definitions:
//
// m.def("my_func", &wrapper<int>, ...)
// m.def("my_func", &wrapper<float>, ...)
//
template <typename T>
py::array_t<T> wrapper(py::array_t<T> input) {
auto proxy = input.template unchecked<1>();
std::vector<T> result = compute_something_returns_vector(proxy);
// give memory cleanup responsibility to the Numpy array
py::capsule free_when_done(result.data(), [](void *f) {
auto foo = reinterpret_cast<T *>(f);
delete[] foo;
});
return py::array_t<T>({result.size()}, // shape
{sizeof(T)}, // stride
result.data(), // data pointer
free_when_done);
}
Наблюдаемые проблемы
Однако, если я вызываю это из Python, я наблюдаю две вещи:(1) данные в выходном массиве являются мусором и (2) когда я вручную удаляю массив Numpy, я получаю следующую ошибку (SIGABRT):
python3(91198,0x7fff9f2c73c0) malloc: *** error for object 0x7f8816561550: pointer being freed was not allocated
Я предполагаю, что эта проблема связана сстрока "delete[] foo
", которая предположительно вызывается с foo
, установленным на result.data()
.Это не способ освободить std::vector
.
Возможные решения
Одним из возможных решений является создание T *ptr = new T[result.size()]
и копирование содержимого result
в этот массив необработанных данных.Однако у меня есть случаи, когда результаты могут быть большими, и я хочу не тратить все это время на выделение и копирование.(Но, возможно, это не так долго, как я думаю.)
Кроме того, я немного знаю о std::allocator
, но, возможно, есть способ выделить необработанные данныемассив, необходимый выходному вектору вне вызова функции compute_something_returns_vector()
, а затем отбрасывать std::vector
впоследствии, сохраняя базовый массив необработанных данных?
Последний вариант - переписать compute_something_returns_vector
.