2 votes

Instancier des objets de type shared_ptr à partir de SWIG en Python

J'ai un BaseClass et certaines classes dérivées

#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__ */

qui sont traitées avec SWIG à la

%module test

%{
#define SWIG_FILE_WITH_INIT
%}

%{
#include "test.h"
%}

%include "test.h"

Ceci peut être utilisé à partir de Python comme

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

Qu'est-ce que Par défaut :

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

Pourquoi ? Le site test.Square() n'est pas assigné à une variable, donc n'existe plus après l'assignation à a y obj_ pointe vers un stockage invalide.

Pour éviter un tel comportement, l'idée est d'utiliser std::shared_ptr<BaseClass> au lieu de BaseClass& c'est-à-dire

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

Ce code exact ne fonctionnera pas cependant avec

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

C'est logique, aussi : test.Square() ne renvoie pas un std::shared_ptr<BaseClass> mais simplement un Square alias BaseClass instance.

Est-il possible d'avoir test.Square() retourne un pointeur partagé std::shared_ptr<Square> ?

5voto

Flexo Points 39273

SWIG est plutôt bon le soutien à std::smart_ptr . Tout se passe de manière assez transparente, de sorte que les modifications que vous devez apporter à votre fichier .i sont simples :

%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"

C'était suffisant pour faire fonctionner votre code Python de démonstration, j'ai également ajouté onlySquare() comme une fonction membre de Square et adapté la démo pour l'illustrer :

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

Cela devrait aussi fonctionner pour les arguments qui ne sont pas des pointeurs intelligents. tous Les instances créées par Python dans cette hiérarchie seront "intelligentes".

(Si cela vous intéresse, j'ai également abordé les sujets suivants std::unique_ptr et std::weak_ptr avant).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X