Jest sporo zakresu robić pożyteczne rzeczy używając generic smart pointer support w SWIG, mimo braku wsparcia odnotowano w C++ 11 notatek.
W skrócie, jeśli istnieje operator->
, wówczas SWIG połączył członków osoby zainteresowanej do wskaźnika, aby umożliwić im używanie zamiennie w języku docelowym przez długi czas.
I już ułożyła kompletny przykład jak to może działać dla Ciebie, używając test.hh poniższym przykładzie pliku hader:
#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();
}
W celu skorzystania z unique_ptr rozsądnie wewnątrz Python miałem napisać następujący plik 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
który zawiera dość podzbioru definicji std::unique_ptr
być użyteczne. (Możesz dodawać lub usuwać konstruktory w zależności od tego, jaką semantykę chcesz zastosować w Pythonie, przeoczyłem tutaj niestandardowe narzędzia do usuwania).
Dodaje także makro wrap_unique_ptr
, które ustawia obsługę. Typografia wymusza na wygenerowanym przez SWIG kodzie użycie konstruktora ruchu zamiast konstruktora kopiowania po powrocie przez wartość.
Możemy używać go w następujący sposób:
%module test
%{
#include "test.hh"
%}
%include "std_unique_ptr.i"
wrap_unique_ptr(FooUniquePtr, Foobar);
%include "test.hh"
Zbudowałem to z:
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
co pozwala nam na stosowanie następującej 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)
Zauważ, że pomimo tego, że jest to unique_ptr<Foobar>
, nadal możemy powiedzieć: a.baz()
i a.wibble
. Metoda release()
zwraca również użyteczny wskaźnik "raw", który jest obecnie własnością Python (ponieważ w przeciwnym razie nie miałby właściciela). get()
zwraca pożyczony wskaźnik wewnątrz Pythona, jak można się spodziewać.
W zależności od tego, jak planujesz używać wskaźników, jest to prawdopodobnie dobry początek dla twoich własnych map i czystszych niż %extend
i release()
wszędzie gdzie masz unique_ptrs.
W porównaniu z %shared_ptr
nie modyfikuje to w mapach typów i nie zmienia konstruktorów w taki sam sposób, w jaki działałaby współużytkowana_ptr. Twoim obowiązkiem jest wybrać, kiedy surowe wskaźniki stają się wciąż unikalnymi_plikami w Pythonie.
Napisałem podobną odpowiedź dla using std::weak_ptr
with SWIG chwilę temu.
Jedną z rzeczy, które można łatwo dodać do ulepszenia, jest typografia dla 'Type *'/'Type &', który może obsłużyć unikalny_ptr lub prawdziwy wskaźnik. – Flexo
Interesujące. Zgadzam się, że jest to o wiele czystsze niż zabrudzanie plików interfejsu z dodatkowymi funkcjami do obsługi konwersji pomiędzy unikalnymi wskaźnikami a surowymi wskaźnikami. Pokazuje również wyraźną intencję właściciela. Dziękuję za szczegółową odpowiedź. – Homar
Uwaga: Moja klasa miała prywatny 'std :: unique_ptr pImpl', w którym to przypadku musiałem ** nie ** zawierać żadnych' wrap_unique_ptr (RealImplUniquePtr, RealImpl) '(które dawałyby błędy o' niekompletnym typie 'od' default_delete'), po prostu umieść typy, które były w pełni dostępne z publicznego interfejsu API. –
unhammer