boost :: python:如何调用一个需要指针的函数?

时间:2010-10-07 12:09:54

标签: python pointers boost-python

我有一个函数,它接受一个int-pointer并通过boost :: python暴露它。如何从python中调用此函数?

在C ++中使用boost :: python:

void foo(int* i);
...
def("foo", foo);

在python中:

import foo_ext
i = 12
foo_ext.foo(i)

结果

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
Boost.Python.ArgumentError: Python argument types in
foo(int)
did not match C++ signature:
foo(int* i)

那么如何传递指针?

3 个答案:

答案 0 :(得分:4)

简短回答:你不能。 Python没有指针

答案很长:根据用例,有各种变通方法。

我注意到你在你的例子中使用了int和int *。 Int(以及float,str和bool)是一种特殊情况,因为它在python中是不可变的。

假设您传入的对象实际上不是int。

有一个包装函数,它将参数作为参考,获取地址并将其传递给实际函数。这将在python中无缝地工作。


好的,所以说它真的是一个int。现在你有问题了。你无法改变你传入的int。如果你尝试相同的解决方案,boost :: python会在运行时抱怨l值。还有几种选择。

假设您不需要在函数退出后看到int的样子,并且您知道该函数在函数返回后不会将指针释放到取消引用:

您的包装器现在应该通过值或const引用获取int。其他一切都是一样的。


也许你只需要看到后状态(int是OUT外围):

您的包装函数现在不带参数,并将本地int的地址传递给实际函数。它将返回该值。如果你的函数已经有一个返回值,它现在应该返回一个元组。


输入和输出都很重要,你知道函数返回后函数不会松开指向取消引用的指针:

结合上面两个。包装器按值获取一个int并返回不同的int。


该函数在函数返回后希望将指针松散到取消引用:

没有真正好的解决方案。您可以在包含c ++ int的c ++中创建和公开对象。包装器将通过引用获取该对象,提取包含的int的地址并将其传递给实际的函数。保持对象在python中保持活动(并且安全地从垃圾收集器)直到库完成它现在是python writer的问题,如果他蠢事,数据损坏或解释器崩溃。

答案 1 :(得分:1)

来自python.org's boost.python HowTo

  

也许你会喜欢结果   Python对象包含原始指针   争论?在那种情况下,   需要注意的是,如果一生的话   C ++对象在之前结束   Python对象,指针将   悬挂和使用Python对象可能   导致崩溃。

     

以下是如何公开可变C ++   模块初始化期间的对象:

scope().attr("a") = object(ptr(&class_instance));

答案 2 :(得分:1)

大多数情况下,您可以避免将原始指针传递给函数,但是当它确实需要时,您可以使用适配器以这种方式为C ++指针创建指向原始对象的Python对象:

template<typename PtrT>
struct PtrAdapter {
    auto& get(PtrT ptr)  { return *ptr; }
};

然后定义指针类型到Python对象的映射并允许隐式转换:

class_<Cluster<LinksT>*, noncopyable>(typpedName<LinksT>("ClusterPtr", true, true)
, "Raw hierarchy cluster pointer\n")
    .def("__call__", &PtrAdapter<Cluster<LinksT>*>::get,
        return_internal_reference<>(),
        "referenced cluster")
    ;
register_ptr_to_python<Cluster<LinksT>*>();

请注意,原始对象类型也应该映射到Python对象(在本例中为Cluster<LinksT>)。

然后是这样的C ++代码:

Cluster<LinksT>* cl = clusters.head();
process(cl);
Id cid = cl->id();

您可以使用类似的Python代码:

cl = clusters.head()
process(cl)
cid = cl.id()