我想知道是否有人对 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;
}
...
但是这个例子不起作用,我没有找到任何可以提供类似功能的构造函数或工厂。
我还想知道:我是否在这里监督了一些显而易见的事情?这是通常不需要的东西吗,因为对于此类问题有更好的解决方案?
如果数据在函数中分配在堆栈中,因此在函数返回后不再有效,则必须通过将 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 日.