Создание объектов shared_ptr из SWIG в Python

python c++ swig

1352 просмотра

1 ответ

У меня есть BaseClassи некоторые производные классы

#ifndef TEST_H__
#define TEST_H__

#include <iostream>
#include <memory>

class BaseClass
{
  public:
  virtual double eval(double x) const = 0;
};

class Square: public BaseClass
{
  public:
  double eval(double x) const {return x*x;}
};

class Add1: public BaseClass
{
  public:
  Add1(BaseClass & obj): obj_(obj) {}

  double eval(double x) const {return obj_.eval(x) + 1.0;}

  private:
  BaseClass & obj_;
};

#endif /* TEST_H__ */

которые лечатся SWIG à la

%module test

%{
#define SWIG_FILE_WITH_INIT
%}

%{
#include "test.h"
%}

%include "test.h"

Это может быть использовано из Python, как

import test
s = test.Square()
a = test.Add1(s)
print(a.eval(2.0))

Что такое segfaulting :

import test
a = test.Add1(test.Square())
print(a.eval(2.0))

Почему? test.Square()Не присваиваются переменным, поэтому больше не существует после присвоения a, а также obj_указует на недопустимое хранение.

Чтобы избежать такого поведения, идея использовать std::shared_ptr<BaseClass>вместо BaseClass&, т.е.

class Add1: public BaseClass
{
  public:
  Add1(std::shared_ptr<BaseClass> & obj): obj_(obj) {}

  double eval(double x) const {return obj_->eval(x) + 1.0;}

  private:
  std::shared_ptr<BaseClass> obj_;
};

Этот точный код не будет работать, хотя с

TypeError: in method 'new_Add1', argument 1 of type 'std::shared_ptr< BaseClass > &'

Имеет смысл также: test.Square()не возвращает, std::shared_ptr<BaseClass>а просто Squareaka BaseClassэкземпляр.

Можно ли test.Square()вернуть общий указатель std::shared_ptr<Square>?

Автор: Nico Schlömer Источник Размещён: 08.11.2019 11:29

Ответы (1)


6 плюса

Решение

SWIG имеет довольно хорошую поддержкуstd::smart_ptr . Все это происходит довольно прозрачно, поэтому изменения, которые нужно внести в свой файл .i, просто:

%module test

%{
#define SWIG_FILE_WITH_INIT
#include "test.h"
%}

%include <std_shared_ptr.i>

%shared_ptr(Square);
%shared_ptr(BaseClass);
%shared_ptr(Add1); // Not actually needed to make your demo work, but a good idea still

%include "test.h"

Этого было достаточно, чтобы заставить ваш демо-код Python работать, я также добавил onlySquare()в качестве функции-члена Squareи адаптировал демо-версию, чтобы проиллюстрировать это:

import test
sq=test.Square()
test.Add1(sq) # implicitly converted to shared_ptr<BaseClass> here
sq.onlySquare()
print sq
# <test.Square; proxy of <Swig Object of type 'std::shared_ptr< Square > *' at 0xf7424950> >

Он должен «просто работать» и для неумных аргументов указателя, но учтите, что теперь все экземпляры, созданные Python в этой иерархии, будут «умными».

(Если вам интересно я тоже освещал std::unique_ptrи std::weak_ptrраньше).

Автор: Flexo Размещён: 20.08.2016 06:36
Вопросы из категории :
32x32