3 回答

TA貢獻(xiàn)1804條經(jīng)驗(yàn) 獲得超8個(gè)贊
我找到了一個(gè)可行的解決方案。雖然它可能不是最優(yōu)雅的。我創(chuàng)建了三個(gè)新類Ints,它們采用原始容器并通過(guò)函數(shù)調(diào)用公開各自的Doubles向量。使用這三個(gè)類,我可以為所有類指定三次緩沖區(qū)協(xié)議。Doubles2getValues()
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/numpy.h>
#include <pybind11/buffer_info.h>
namespace py = pybind11;
struct ContainerElement
{
uint8_t i;
double d;
double d2;
};
class Container
{
private:
std::vector<uint8_t> ints;
std::vector<double> doubles;
std::vector<double> doubles2;
public:
std::vector<uint8_t>& getInts() { return ints; }
std::vector<double>& getDoubles() { return doubles; }
std::vector<double>& getDoubles2() { return doubles2; }
void addElement(ContainerElement element)
{
ints.emplace_back(element.i);
doubles.emplace_back(element.d);
doubles2.emplace_back(element.d2);
}
};
void fillContainer(Container& container)
{
for (int i = 0; i < 1e6; ++i)
{
container.addElement({ (uint8_t)i, (double)i,(double)i });
}
}
class Ints
{
private:
Container& cont;
public:
Ints(Container& cont) : cont(cont) {}
std::vector<uint8_t>& getValues() { return cont.getInts(); }
};
class Doubles
{
private:
Container& cont;
public:
Doubles(Container& cont) : cont(cont) {}
std::vector<double>& getValues() { return cont.getDoubles(); }
};
class Doubles2
{
private:
Container& cont;
public:
Doubles2(Container& cont) : cont(cont) {}
std::vector<double>& getValues() { return cont.getDoubles2(); }
};
PYBIND11_MODULE(newInterface, m) {
py::class_<Container>(m, "Container")
.def(py::init<>());
py::class_<Ints>(m, "Ints", py::buffer_protocol())
.def(py::init<Container&>(), py::keep_alive<1, 2>())
.def_buffer([](Ints& ints) -> py::buffer_info {
return py::buffer_info(
ints.getValues().data(),
sizeof(uint8_t),
py::format_descriptor<uint8_t>::format(),
ints.getValues().size()
);
});
py::class_<Doubles>(m, "Doubles", py::buffer_protocol())
.def(py::init<Container&>(), py::keep_alive<1, 2>())
.def_buffer([](Doubles& doubles) -> py::buffer_info {
return py::buffer_info(
doubles.getValues().data(),
sizeof(double),
py::format_descriptor<double>::format(),
doubles.getValues().size()
);
});
py::class_<Doubles2>(m, "Doubles2", py::buffer_protocol())
.def(py::init<Container&>(), py::keep_alive<1, 2>())
.def_buffer([](Doubles2& doubles2) -> py::buffer_info {
return py::buffer_info(
doubles2.getValues().data(),
sizeof(double),
py::format_descriptor<double>::format(),
doubles2.getValues().size()
);
});
m.def("fillContainer", &fillContainer);
}
這樣我就可以在 Python 中按以下方式使用代碼:
import newInterface as ci
import numpy as np
container = ci.Container()
ci.fillContainer(container)
i = np.array(ci.Ints(container), copy=False)
d = np.array(ci.Doubles(container), copy=False)
d2 = np.array(ci.Doubles2(container), copy=False)
一旦fillContainer填充了容器,numpy 數(shù)組的構(gòu)造就不會(huì)從這個(gè)容器中復(fù)制值。

TA貢獻(xiàn)1796條經(jīng)驗(yàn) 獲得超4個(gè)贊
我猜您必須指定訪問(wèn)函數(shù)返回引用而不是副本,這可能是默認(rèn)值。我不知道你是如何用 pybind 做到這一點(diǎn)的,但我已經(jīng)用 boost::python 和Ponder做到了這一點(diǎn)。
即您需要指定退貨政策。

TA貢獻(xiàn)1772條經(jīng)驗(yàn) 獲得超5個(gè)贊
這并不能直接解決問(wèn)題,但仍然允許在不進(jìn)行復(fù)制的情況下返回?cái)?shù)組緩沖區(qū)。靈感來(lái)自這個(gè)線程: https ://github.com/pybind/pybind11/issues/1042
基本上,只需向 py::array() 構(gòu)造函數(shù)提供一個(gè) py::capsule。這樣,py::array() 構(gòu)造函數(shù)就不會(huì)分配單獨(dú)的緩沖區(qū)和副本。例如:
// Use this if the C++ buffer should NOT be deallocated
// once Python no longer has a reference to it
py::capsule buffer_handle([](){});
// Use this if the C++ buffer SHOULD be deallocated
// once the Python no longer has a reference to it
// py::capsule buffer_handle(data_buffer, [](void* p){ free(p); });
return py::array(py::buffer_info(
data_buffer,
element_size,
data_type,
dims_length,
dims,
strides
), buffer_handle);
添加回答
舉報(bào)