Es ist ziemlich viel Spielraum nützliche Dinge zu tun, um die generic smart pointer support in SWIG mit, trotz der erwähnten Mangel an Unterstützung in den C++ 11 Noten.
Kurz gesagt, wenn es eine operator->
gibt, hat SWIG die Mitglieder des pointee in den Zeiger zusammengeführt, damit sie für eine lange Zeit austauschbar innerhalb der Zielsprache verwendet werden können.
Ich habe ein vollständiges Beispiel zusammen, wie dies für Sie arbeiten könnte, unter dem Beispiel hader Datei test.hh mit:
#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();
}
Um die unique_ptr vernünftig innerhalb Python zu verwenden, schreibe ich musste die folgende SWIG Datei, 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
Welche genug von einer Teilmenge der Definition von std::unique_ptr
enthält, nützlich sein. (Sie können Konstruktoren hinzufügen oder entfernen, je nachdem, welche Semantik Sie in Python haben wollen, ich habe die benutzerdefinierten Deleters hier übersehen).
Es fügt auch ein Makro wrap_unique_ptr
hinzu, das die Unterstützung einrichtet. Die Typenkarte erzwingt nur, dass der generierte SWIG-Code bei der Rückgabe nach Wert den Verschiebungskonstruktor anstelle des Kopierkonstruktors verwendet.
Wir können es auf folgende Weise verwenden:
%module test
%{
#include "test.hh"
%}
%include "std_unique_ptr.i"
wrap_unique_ptr(FooUniquePtr, Foobar);
%include "test.hh"
Ich baute diese mit:
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
Was uns die folgende Python verwenden können:
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)
Beachten Sie, dass Obwohl wir ein unique_ptr<Foobar>
sind, können wir immer noch a.baz()
und a.wibble
sagen. Die Methode release()
gibt auch einen verwendbaren 'rohen' Zeiger zurück, der jetzt Python gehört (da er sonst keinen Eigentümer hätte). get()
gibt wie erwartet einen ausgeliehenen Zeiger in Python zurück.
Je nachdem, wie Sie die Zeiger verwenden möchten, ist dies wahrscheinlich ein guter Anfang für Ihre eigenen Typmaps und sauberer als ein %extend
und release()
überall wo Sie unique_ptrs haben.
Im Vergleich zu %shared_ptr
ändert dies nicht die in typesmaps und es ändert nicht die Konstruktoren in der gleichen Weise die shared_ptr Unterstützung würde. Es liegt in Ihrer Verantwortung zu wählen, wann rohe Zeiger in Python immer noch unique_ptrs werden.
Ich schrieb eine ähnliche Antwort für using std::weak_ptr
with SWIG eine Weile zurück.
Eines der Dinge, die einfach hinzugefügt werden könnten, wäre in typemap für 'Type *'/'Type &', das entweder mit einem unique_ptr oder einem echten Zeiger umgehen kann. – Flexo
Interessant. Ich stimme zu, dass dies viel sauberer ist, als die Interface-Dateien mit zusätzlichen Funktionen zu überfrachten, um Konvertierungen zwischen unique_ptrs und rohen Pointern zu handhaben. Es zeigt auch klare Eigentumsabsicht. Danke für die ausführliche Antwort. – Homar
Anmerkung: Meine Klasse hatte eine private 'std :: unique_ptr pImpl', in diesem Fall musste ich ** nicht ** irgendwelche' wrap_unique_ptr (RealImplUniquePtr, RealImpl) 'einschließen (das würde Fehler über 'unvollständiger Typ' von' geben default_delete'), umschließen Sie einfach die Typen, die von der öffentlichen API vollständig verfügbar waren. –
unhammer