使用拥有的内存返回nanobind中的ndarray

问题描述 投票:0回答:1

我想知道是否有人对 nanobind 有深入的了解,以将

ndarray
从 c++ 返回到 python。

我只是想返回一个给定大小的

ndarray
,我用数据填充它。我不想用c++管理内存。所以我会做类似的事情:

...
.def("test", []() {
   std::array a {10.0, 20.0};
   return nanobind::ndarray<nb::numpy, double>(a.data(), { a.size() }, nanobind::handle());
})
...

虽然这似乎有效,但我不确定它是否正确,或者我是否引入了内存泄漏,并且数组指向离开函数后释放的内存。在文档中讨论了所有权和创建一个处理内存的胶囊。虽然这对于大型数组可能有意义,但对于小型数组来说似乎过于复杂。

还有一个示例,其中仅

nanobind::handle()
(如上面的片段所示)用作所有者,但在特定示例中,底层数据无论如何都不会被释放,因为它是在全局空间中定义的。

作为替代方案,可以考虑先创建一个

ndarray
,它分配内存,然后填充它。类似的东西

...
.def("test", []() {
   nb::ndarray<nb::numpy, nb::shape<100>, double> result; // array with allocated memory
   std::span<double> view(result.data(), result.data()+result.size(); 
   std::fill(view.begin(), view.end(), 100); // arbitrary function to fill the ndarray ....
   return result;
}
...

但是这个例子不起作用,我没有找到任何可以提供类似功能的构造函数或工厂。

我还想知道:我是否在这里监督了一些显而易见的事情?这是通常不需要的东西吗,因为对于此类问题有更好的解决方案?

python numpy-ndarray nanobind
1个回答
0
投票

如果数据在函数中分配在堆栈中,因此在函数返回后不再有效,则必须通过将 ndarray 转换为 python 对象来返回数据的副本。

根据此处找到的最新文档,https://nanobind.readthedocs.io/en/latest/ndarray.html#returning-temporaries,您可以省略或使用 nullptr 作为所有者,只要返回值策略函数绑定的参数是 rv_policy::automatic (默认)或 rv_policy::automatic_reference,nanobind 将返回数据的副本。 (https://nanobind.readthedocs.io/en/latest/ndarray.html#return-value-policies)即使数据未分配堆栈也是如此。

对于堆栈分配的内存,您还应该在返回之前将 ndarray 转换为 python 对象,使用 nb::cast 或 ndarray .cast() 方法,这会强制在函数返回之前进行复制。直到函数返回后才会发生自动转换;当堆栈分配的内存不再有效时。

您的第一个函数可能类似于:

...
.def("test", []() {
   std::array a {10.0, 20.0};
   return nanobind::ndarray<nb::numpy, double>(a.data(), { a.size() }, nullptr).cast();
})
...

注意,ndarray .cast() 方法是在版本 2.2.0(2024 年 10 月 3 日)中引入的 https://nanobind.readthedocs.io/en/latest/changelog.html#version-2-2-0- 2024 年 10 月 3 日.

© www.soinside.com 2019 - 2024. All rights reserved.