Там довольно много возможностей, чтобы сделать полезные вещи, используя generic smart pointer support в SWIG, несмотря на отметили отсутствие поддержки в примечаниях C++ 11.
Вкратце, если есть operator->
, тогда SWIG объединил членов указателя в указатель, чтобы они долгое время использовались в пределах целевого языка.
Я собрал полный пример того, как это может работать для вас, используя пример Hader файл test.hh ниже:
#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();
}
Для того, чтобы использовать unique_ptr благоразумно внутри Python я должен был написать следующий 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
, это не изменяет в typemaps и не изменяет конструкторы таким же образом, как и поддержка shared_ptr. Вы несете ответственность за выбор, когда raw-указатели становятся уникальными в Python.
Я написал аналогичный ответ за using std::weak_ptr
with SWIG некоторое время назад.
. Одна из вещей, которую было бы легко добавить, чтобы улучшить это, будет в печатной карте для типа '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' или '' – Flexo
Интересно. Я согласен с тем, что это намного чище, чем мутирование файлов интерфейса с дополнительными функциями для обработки конверсий между уникальными указателями unique_ptr и raw. Он также показывает явное намерение собственности. Спасибо за подробный ответ. – Homar
Примечание: у моего класса был приватный 'std :: unique_ptr pImpl', и в этом случае я должен был ** не ** включать какие-либо' wrap_unique_ptr (RealImplUniquePtr, RealImpl) '(что бы приводило к ошибкам о' неполном типе 'от ' default_delete'), просто оберните типы, которые были полностью доступны из общедоступного API. –
unhammer