如何使用SWIG处理unique_ptr [英] How to handle unique_ptr's with SWIG

查看:51
本文介绍了如何使用SWIG处理unique_ptr的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个实现发布-订阅模式的 EventDispatcher 类.它的界面看起来像这样(简化):

I have an EventDispatcher class that implements the publish-subscribe pattern. It's interface looks something like this (simplified):

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文档指出:

I want to expose this class to Python. The latest SWIG documentation states that:

没有可用于std :: weak_ptr的特殊智能指针处理还有std :: unique_ptr.

There is no special smart pointer handling available for std::weak_ptr and std::unique_ptr yet.

我很想至少能够继续在c ++端使用unique_ptr.我有什么选择?

I would quite like to at least be able to continue using unique_ptr's on the c++ side. What are my options?

我考虑过使用SWIG的%extend功能扩展类,但是我无法使用此方法访问私有成员( m_subscriptions ).

I considered extending the class using SWIG's %extend feature, but I am unable to access private members (m_subscriptions) using this method.

我看到的唯一另一个选择是使用SWIG预处理器定义其他方法 swig_publish swig_subscribe ,但这会使我的界面文件杂乱无章.

The only other option I can see is to use the SWIG preprocessor to define extra methods, swig_publish and swig_subscribe, but this clutters my interface file.

推荐答案

使用简而言之,如果有 operator-> ,那么SWIG会将pointee的成员合并到指针中,以使它们可以在目标语言中长时间互换使用.

In short if there's an operator-> then SWIG has merged the members of the pointee into the pointer to allow them to be used interchangeably within the the target language for a long time.

我已经使用下面的示例hader文件test.hh整理了一个完整的示例,说明了该方法如何为您工作:

I've put together a complete example of how this might work for you, using the example hader file test.hh below:

#include <memory>
#include <iostream>

struct Foobar {
  void baz() { std::cout << "This works\n"; }
  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:

In order to use the unique_ptr sensibly inside Python I had to write the following SWIG file, 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中确切想要的语义来添加或删除构造函数,我在这里忽略了自定义删除器).

Which includes enough of a subset of the definition of std::unique_ptr to be useful. (You can add or remove constructors depending on exactly what semantics you want within Python, I overlooked the custom deleters here).

它还添加了一个宏 wrap_unique_ptr 来设置支持.当按值返回时,类型映射只是强制SWIG的生成代码使用move构造函数而不是copy构造函数.

It also adds a macro wrap_unique_ptr that sets up the support. The typemap just forces SWIG's generated code to use the move constructor instead of the copy constructor when returning by value.

我们可以通过以下方式使用它:

We can use it in the following way:

%module test

%{
#include "test.hh"
%}

%include "std_unique_ptr.i"

wrap_unique_ptr(FooUniquePtr, Foobar);

%include "test.hh"

我用以下方法构建了这个容器:

I built this with:

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:

Which allows us to use the following 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内部的借入指针,如您所愿.

Notice that despite being a unique_ptr<Foobar> we can still say a.baz() and a.wibble. The release() method also returns a usable 'raw' pointer, which is owned by Python now (since otherwise it wouldn't have an owner). get() returns a borrowed pointer inside Python as you'd expect.

取决于您打算如何使用指针,这可能是您自己的类型映射和清理程序的一个好开始,而不是随处都有的%extend release()unique_ptrs.

Depending on quite how you plan to use the pointers this is probably a good start for your own typemaps and cleaner than a %extend and release() everywhere you have unique_ptrs.

%shared_ptr 相比,它不会修改typemap中的in,并且不会像shared_ptr支持那样更改构造函数.您有责任选择在Python内原始指针何时仍变为unique_ptrs.

Compared to %shared_ptr, this doesn't modify the in typemaps and it doesn't change the constructors in the same way the shared_ptr support would. It's your responsibility to choose when raw pointers become unique_ptrs within Python still.

我为使用 std :: weak_ptr 和SWIG 写了类似的答案

这篇关于如何使用SWIG处理unique_ptr的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆