当将C++与pybind11绑定时,我遇到了一个问题,涉及两个返回(const或non—const)引用的类成员;考虑以下代码段:

struct Data {
    double value1;
    double value2;
};

class Element {
 public:
    Element() = default;
    Element(Data values) : data(values) { }
    Element(const Element& other) : data(other.data) { printf("copying from %p\n", &other); }

    Data data;
};

class Container {
 public:
    Container() : data(10, Element(Data{0.1, 0.2})) {};

    Element& operator[](size_t idx) { return data[idx]; }
    const Element& operator[](size_t idx) const { return data[idx]; }

 protected:
    std::vector< Element > data;
};

它被绑定到一个Python模块,其中包含:

py::class_< Data > (module, "Data")
    .def(py::init< double, double >(), "Constructs a new instance", "v1"_a, "v2"_a)
    .def_readwrite("value1", &Data::value1)
    .def_readwrite("value2", &Data::value2);

py::class_< Element > (module, "Element")
    .def(py::init< Data >(), "Constructs a new instance", "values"_a)
    .def_readwrite("data", &Element::data)
    .def("__repr__", [](const Element& e){ return std::to_string(e.data.value1); });

py::class_< Container > (module, "Container")
    .def(py::init< >(), "Constructs a new instance")
    .def("__getitem__", [](Container& c, size_t idx) { return c[idx]; }, "idx"_a)
    .def("__setitem__", [](Container& c, size_t idx, Element e) { c[idx] = e; }, "idx"_a, "val"_a);

我在让[]接线员在Container班工作时遇到了麻烦

print("-------------")
foo = module.Data(0.9, 0.8)
print(foo.value2)
foo.value2 = 0.7    # works
print(foo.value2)

print("-------------")
e = module.Element(motion.Data(0.3, 0.2))
print(e.data.value1)
e.data.value2 = 0.6    # works
print(e.data.value2)
e.data = foo           # works
print(e.data.value2)

print("-------------")
c = motion.Container()
print(c[0].data.value1)
c[0] = e                   # works
print(c[0].data.value1)
c[0].data = foo            # does not work (!)
print(c[0].data.value1)
c[0].data.value1 = 0.0     # does not work (!)
print(c[0].data.value1)

虽然__getitem__([])函数看起来确实像预期的那样工作,但在访问返回对象上的成员时似乎失败了;相反,从返回的引用创建临时副本,并且不应用对该实例的任何更改. 我try 了1)在绑定Element类时声明std::shared_ptr<Element>持有者类型;2)在__getitem__上定义特定的返回值策略py::return_value_policy::referencepy::return_value_policy::reference_internal;以及3)定义特定的调用策略py::keep_alive<0,1>()py::keep_alive<1,0>();但这些解决方案都不起作用.

有什么建议如何解决这个问题吗?

推荐答案

C++推导出你的lambda的返回类型是Element而不是Element&,这样做了一个复制,所以明确定义了返回类型,并确保你也通过引用来获取项以避免复制.

    py::class_< Container > (module, "Container")
    .def(py::init< >(), "Constructs a new instance")
    .def("__getitem__", [](Container& c, size_t idx) ->Element& { return c[idx]; }, "idx"_a, py::return_value_policy::reference_internal)
    .def("__setitem__", [](Container& c, size_t idx, const Element& e) { c[idx] = e; }, "idx"_a, "val"_a);

如果使用C++14或更高版本,则可以将返回类型定义为->auto&.

Python相关问答推荐

我在使用fill_between()将最大和最小带应用到我的图表中时遇到问题

对某些列的总数进行民意调查,但不单独列出每列

Python 约束无法解决n皇后之谜

大小为M的第N位_计数(或人口计数)的公式

部分视图的DataFrame

Python脚本使用蓝牙运行在Windows 11与raspberry pi4

Python导入某些库时非法指令(核心转储)(beautifulsoup4."" yfinance)

Tkinter菜单自发添加额外项目

在单次扫描中创建列表

从一个df列提取单词,分配给另一个列

如何在Python中将超链接添加到PDF中每个页面的顶部?

应用指定的规则构建数组

获取git修订版中每个文件的最后修改时间的最有效方法是什么?

在我融化极点数据帧之后,我如何在不添加索引的情况下将其旋转回其原始形式?

如何编辑此代码,使其从多个EXCEL文件的特定工作表中提取数据以显示在单独的文件中

高效生成累积式三角矩阵

Regex用于匹配Python中逗号分隔的AWS区域

我可以同时更改多个图像吗?

将参数从另一个python脚本中传递给main(argv

IpyWidget Select 框未打开