如何使用SWIG处理unique_ptr
How to handle unique_ptr's with SWIG
我有一个实现发布-订阅模式的EventDispatcher
类。它的界面看起来像这样(简化):
class EventDispatcher
{
public:
void publish(const std::string& event_name, std::unique_ptr<Event> event);
std::unique_ptr<Subscription> subscribe(const std::string& event_name, std::unique_ptr<Callback> callback);
private:
std::unordered_map<std::string, std::vector<std::unique_ptr<Callback>>> m_subscriptions;
}
我想向 Python 公开这个类。最新的SWIG文档指出:
没有特殊的智能指针处理可用于 std::weak_ptr 和标准::unique_ptr还没有。
我非常希望至少能够在 c++ 端继续使用 unique_ptr。我有哪些选择?
我考虑过使用 SWIG 的 %extend 功能扩展类,但我无法使用此方法访问私有成员(m_subscriptions
)。
我能看到的唯一其他选择是使用 SWIG 预处理器来定义额外的方法,swig_publish
和swig_subscribe
,但这会使我的界面文件混乱。
尽管 C++11 注释中指出缺乏支持,但使用 SWIG 中的通用智能指针支持做有用的事情的空间很大。
简而言之,如果有operator->
那么SWIG将pointee的成员合并到指针中,以允许它们在目标语言中
我整理了一个完整的示例,说明这可能如何为您工作,使用下面的示例 hader file test.hh:
#include <memory>
#include <iostream>
struct Foobar {
void baz() { std::cout << "This worksn"; }
int wibble;
};
std::unique_ptr<Foobar> make_example() {
return std::unique_ptr<Foobar>(new Foobar);
}
void dump_example(const std::unique_ptr<Foobar>& in) {
std::cout << in->wibble << "n";
in->baz();
}
为了在Python中明智地使用unique_ptr,我必须编写以下SWIG文件std_unique_ptr.i:
namespace std {
%feature("novaluewrapper") unique_ptr;
template <typename Type>
struct unique_ptr {
typedef Type* pointer;
explicit unique_ptr( pointer Ptr );
unique_ptr (unique_ptr&& Right);
template<class Type2, Class Del2> unique_ptr( unique_ptr<Type2, Del2>&& Right );
unique_ptr( const unique_ptr& Right) = delete;
pointer operator-> () const;
pointer release ();
void reset (pointer __p=pointer());
void swap (unique_ptr &__u);
pointer get () const;
operator bool () const;
~unique_ptr();
};
}
%define wrap_unique_ptr(Name, Type)
%template(Name) std::unique_ptr<Type>;
%newobject std::unique_ptr<Type>::release;
%typemap(out) std::unique_ptr<Type> %{
$result = SWIG_NewPointerObj(new $1_ltype(std::move($1)), $&1_descriptor, SWIG_POINTER_OWN);
%}
%enddef
其中包括足够多的std::unique_ptr
定义的子集是有用的。(您可以根据 Python 中所需的语义添加或删除构造函数,我在这里忽略了自定义删除器)。
它还添加了一个宏wrap_unique_ptr
来设置支持。类型映射只是强制 SWIG 生成的代码在按值返回时使用移动构造函数而不是复制构造函数。
我们可以通过以下方式使用它:
%module test
%{
#include "test.hh"
%}
%include "std_unique_ptr.i"
wrap_unique_ptr(FooUniquePtr, Foobar);
%include "test.hh"
我用:
swig3.0 -py3 -c++ -python -Wall test.i
g++ -Wall -Wextra -Wno-missing-field-initializers test_wrap.cxx -std=c++11 -I/usr/include/python3.4/ -lpython3.4m -shared -o _test.so
这允许我们使用以下 Python:
from test import *
a = make_example()
print(a)
a.wibble = 1234567
a.baz()
dump_example(a)
a.baz()
print(bool(a))
print(bool(FooUniquePtr(None)))
b=a.release()
print(b)
请注意,尽管是unique_ptr<Foobar>
但我们仍然可以说 a.baz()
和 a.wibble
.release()
方法还返回一个可用的"原始"指针,该指针现在归 Python 所有(因为否则它就没有所有者)。 get()
如您所期望的那样在 Python 中返回一个借用的指针。
根据您计划如何使用指针,对于您自己的排版图和清洁器来说,这可能是一个好的开始,而不是%extend
和release()
您unique_ptrs的任何地方。
与%shared_ptr
相比,这不会修改in类型映射,也不会像shared_ptr支持那样更改构造函数。你有责任选择原始指针何时在 Python 中变得unique_ptrs。
不久前,我为将std::weak_ptr
与SWIG一起使用写了一个类似的答案。
是,似乎可以%ignore
一个函数,%extend
该类来定义被忽略函数的替代实现,并最终从该函数的替代实现中调用最初忽略的函数。例如:
%ignore EventDispatcher::subscribe(const std::string&, std::unique_ptr<Callback>);
%include "EventDispatcher.hpp"
%extend suborbital::EventDispatcher
{
EventSubscription* EventDispatcher::subscribe(const std::string& event_name, PyObject* callback)
{
std::unique_ptr<Callback> callback_ptr(new Callback(callback));
return $self->subscribe(event_name, std::move(callback_ptr)).release();
}
}
SWIG-4.1 添加了 std::unique_ptr 支持。https://swig.org/Doc4.1/Library.html#Library_std_unique_ptr 的文档。
目前尚不支持unique_ptr。http://www.swig.org/Doc3.0/CPlusPlus11.html
您需要使用智能指针,如下所示:http://www.swig.org/Doc3.0/Library.html#Library_std_shared_ptr
- 为什么 std::unique 不调用 std::sort?
- CLANG 编译器 说:变量"PTR"可能未初始化
- 在以唯一ptr为值的C++映射中,动态内存何时会被销毁
- 将 ptr 传递给 ptr 到 A 作为参数传递给 A 的函数是不好的做法吗?
- 为共享 ptr 向量实现复制 c'tor?
- 字符和整数中 **(ptr+1) 的值差异
- C++:在不中断共享的情况下通过引用传递共享 PTR?
- 生成"unique"矩阵
- 如何将派生类从基 ptr 分配给 nlohmann::json
- 引用 std::shared:ptr 以避免引用计数
- 我对 std::unique(算法)C++有问题
- 为什么我不能在不进行任何转换的情况下将浮点数放入任何类型的 ptr 中?
- 在调用函数时,ptr** 和 ptr*& 之间是否有区别,或者首选C++?
- 另一种类型的智能ptr,比如具有弱refs的unique_ptr
- 尝试打印出 *ptr++ 的值,以了解它是如何工作的
- 如何控制共享 ptr 引用计数?
- std::shared_ptr::unique(),复制和线程安全
- 如何在C++03中用自定义谓词调用std::unique
- C++中的指针否定 (!ptr == NULL)
- C++14 unique_ptr并使用已删除的函数'std::unique-ptr' unique_ptr错误