2014-12-29 2 views
5

publish-subscribe 패턴을 구현하는 EventDispatcher 클래스가 있습니다.SWIG를 사용하여 unique_ptr을 처리하는 방법

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; 
} 

내가 파이썬이 클래스를 노출 할 : 그것은 인터페이스를 이런 식으로 뭔가 (간체)을 보이는입니다.

이 표준을 사용할 수 처리 특별한 스마트 포인터 :: 및 표준 :: unique_ptr weak_ptr를 아직 없다 : 최신 꿀꺽 꿀꺽 문서는 상태.

적어도 C++ 측에서 unique_ptr을 계속 사용하고 싶습니다. 내 옵션은 무엇입니까?

SWIG의 % 확장 기능을 사용하여 클래스를 확장하는 것을 고려했지만이 방법을 사용하여 전용 멤버 (m_subscriptions)에 액세스 할 수 없습니다.

내가 볼 수있는 유일한 다른 옵션은 여분의 메소드 인 swig_publishswig_subscribe을 정의하기 위해 SWIG 전 처리기를 사용하는 것입니다. 그러나 이것은 내 인터페이스 파일을 혼란스럽게합니다.

답변

10

범위를 꽤 많이는 C++ 11 노트 지원의주의 부족에도 불구하고, SWIG의 generic smart pointer support을 사용하여 유용한 일을 할 수있다.

간단히 말해서 operator->이있는 경우 SWIG는 pointee 멤버를 포인터로 병합하여 오랜 시간 동안 대상 언어 내에서 상호 교환 할 수있게 사용합니다.

내가 함께이 아래의 예 hader 파일 test.hh을 사용하여, 당신을 위해 작동하는 방법의 전체 예제를 넣어했습니다 내가 써야했다 파이썬 내부 현명 unique_ptr을 사용하려면

#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(); 
} 

다음 꿀꺽 꿀꺽 파일, 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의 정의의 부분 집합을 충분히 포함 유용합니다. (파이썬에서 원하는 의미론에 따라 생성자를 추가하거나 제거 할 수 있습니다. 여기에서 사용자 정의 삭제자를 간과했습니다.)

또한 지원을 설정하는 매크로 wrap_unique_ptr을 추가합니다. typemap은 값으로 반환 할 때 SWIG의 생성 된 코드가 복사 생성자 대신 이동 생성자를 사용하도록합니다.

우리는 다음과 같은 방법으로 사용할 수 있습니다 : 다음 파이썬 사용할 수있게 해준다

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 

:

%module test 

%{ 
#include "test.hh" 
%} 

%include "std_unique_ptr.i" 

wrap_unique_ptr(FooUniquePtr, Foobar); 

%include "test.hh" 

내가 이것을 내장

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() 메서드는 또한 파이썬이 현재 소유하고있는 사용 가능한 '원시'포인터를 반환합니다. 그렇지 않으면 소유자가 없으므로 사용할 수 있습니다. get()은 예상대로 Python에서 빌린 포인터를 반환합니다.

포인터를 어떻게 사용 하느냐에 따라 unique_ptrs가있는 모든 곳의 %extendrelease()보다 자신의 typemaps 및 클리너에 대한 유용한 시작이 될 것입니다.

%shared_ptr과 비교하여 typemap을 수정하지 않으며 shared_ptr 지원과 동일한 방법으로 생성자를 변경하지 않습니다. 원시 포인터가 파이썬 안에서 여전히 unique_ptrs가 될 때를 선택하는 것은 당신의 책임입니다.

나는 using std::weak_ptr with SWIG에 대해 비슷한 답변을 작성했습니다.

+0

향상시키기 위해 추가하기 쉬운 사항 중 하나는 typemap unique_ptr이나 실수 포인터를 처리 할 수있는'Type *'/'Type &'에 대해. – Flexo

+0

흥미 롭습니다. unique_ptr과 raw 포인터 사이의 변환을 처리하는 추가 함수로 인터페이스 파일을 muddying하는 것보다 훨씬 깔끔하다는 것에 동의합니다. 또한 명확한 소유권을 나타냅니다. 상세한 답변을 해줘서 고맙습니다. – Homar

+0

참고 : 클래스에는 개인 std :: unique_ptr pImpl'이 있습니다.이 경우에는'wrap_unique_ptr (RealImplUniquePtr, RealImpl)'을 포함하지 않아야합니다. (''불완전한 타입' default_delete'), 공용 API에서 완전히 사용할 수있는 유형을 랩핑하면됩니다. – unhammer

-2

아직 unique_ptr을 (를) 지원하지 않습니다. http://www.swig.org/Doc3.0/CPlusPlus11.html

당신은 다음과 같이 스마트 포인터를 사용해야합니다 http://www.swig.org/Doc3.0/Library.html#Library_std_shared_ptr

+0

다른 형식의 스마트 포인터를 사용하고 싶지는 않습니다. unique_ptr을 C++ 측에서 계속 사용하면서 원시 포인터를 사용하는 다른 함수를 Python에 노출시키는 방법에 관심이 있습니다. – Homar

2

기이, 함수가 호출 마지막으로 무시 기능의 대체 구현을 정의 할 수있는 클래스, %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(); 
    } 
} 
+0

.i 파일의 원래 함수 프로토 타입에 노출 (선언)하지 않는 한 % ignore를 호출하지 않고 직접이 작업을 수행 할 수 있습니다. – n00shie

관련 문제