【问题标题】:boost.python caching wrapped class membersboost.python 缓存包装的类成员
【发布时间】:2016-08-08 10:26:49
【问题描述】:

我有一个琐碎的类依赖:

class A {
    ... // constructor is omitted 
public:
    const std::string str1;
};
class B {
public:
    std::shared_ptr<A> a;
}

BOOST_PYTHON_IMPORT(wrapped) {

    class_<A, std::shared_ptr<A>>("APy")
    .def_readonly("str1", &A::str1);

    class_<B>("BPy")
    .def_readwrite("a", &B::a);
}

在 Python 中

import wrapped as wr
b = wr.BPy()
s1 = b.a.str1 // APy wrapper created
s2 = b.a.str1 // new APy wrapper created even though object is the same

有没有办法为一个对象创建一次这个 APy 包装器? 特别是,因为内部对象 A 是不可变的(在这种特殊情况下)。 否则,创建大量此类临时对象会产生相当大的开销。

【问题讨论】:

标签: c++ boost boost-python


【解决方案1】:

APy 包装器是临时的,因为 s1, s2 是字符串。一旦创建了s1,Python 并不关心创建它的设置是否也可以用于创建s2。很可能b.a 被丢弃,因为它没有被存储。 当你做类似的事情时会发生同样的事情

a1 = b.a
s1 = a1.str1
s2 = a1.str1

?

更新:

我们正试图找出 b.a 在 Python 中的实际含义。

你的调用是

BOOST_PYTHON_IMPORT(wrapped) {

    class_<A, std::shared_ptr<A>>("APy")
    .def_readonly("str1", &A::str1);

    class_<B>("BPy")
    .def_readwrite("a", &B::a);
}

def_readwriteboost/python/class.hpp中的定义是

template <class D>
self& def_readwrite(char const* name, D const& d, char const* doc=0)
{
    return this->def_readwrite_impl(name, d, doc BOOST_PYTHON_DATA_MEMBER_HELPER(D));
}
// translates to
class_<B>& def_readwrite(char const* name, A &d,
  char const* doc=0, detail::is_data_member_pointer<B>()){...}

def_readwrite_impl 的最佳匹配实现在哪里

class_<B>& def_readwrite_impl(char const* name, A B::*a,
  char const* doc, mpl::true_) 

因为B::*a 应该是 B 的成员,而不是函数指针。这反过来又调用了

class_<B>& def_readwrite_impl(char const* name, A B::*pm_, char const* doc, mpl::true_)

pm_ 是指向某个 B 类型对象的成员的未绑定指针。 现在,让我们转到add_property

class_<B>& add_property(char const* name, A &fget = B::*a,
  A &fset = B::*a, char const* docstr = 0)

从这里我们去 boost/python/objects/class.hpp 看看class_base::add_property:

void add_property(char const* name, 
    object const& fget, object const& fset, char const* docstr);

不幸的是,实现被隐藏了。但签名表明魔法发生在make_getter

template <class F>
object make_getter(F f)
{
    typedef typename api::is_object_operators<F>::type is_obj_or_proxy;

    return this->make_fn_impl(
        detail::unwrap_wrapper((W*)0)
      , f, is_obj_or_proxy(), (char*)0, detail::is_data_member_pointer<F>()
    );
}

unwrap_wrapper 没有对指针做任何事情,因为std::shared_ptr 不是从boost::python::wrapper 派生的。 is_data_member_pointer 已经是第一个宏的一部分。我不确定这是否是您案例中的问题,因为在某些时候挖掘更多装饰器变得非常乏味。

在寻找一些装饰器定义时,我偶然发现了坏消息。将其作为评论添加到您的原始问题中。

【讨论】:

  • 字符串应该被认为是POD类型。问题是 boost.python 是否有某种机制来存储创建的包装器,而不是每次都创建副本。
  • @AlexandraB。这取决于a 是否真的被视为数据。如果它被视为一个访问函数,它将被这样调用。我将在当天晚些时候更深入地研究definition of def_readwrite。到目前为止,我只找到了更多的生成器,而不是实际存储的东西。
  • “对指针做任何事情”是什么意思?我想这些签名并没有“解释”如何管理 getter 的返回值。这就是问题所在:获取成员变量(其包装器)时是否涉及任何缓存(返回的对象生命周期跟踪)?
  • “对指针做任何事情”:包装器类型被解包,暴露了原始指针。这不适用于std::smart_ptr,因为Boost 仅将boost::smart_ptr 识别为包装器(标准是从boost::python::wrapper 继承)。这似乎是Boost中的一个错误。 The ticket on Boost GitHub seems to be in beta phase, reopened three times. Boost 版本的错误修复了吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-02
  • 1970-01-01
  • 2016-03-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多