在Python中从SWIG实例化shared_ptr对象

Instantiate shared_ptr objects from SWIG in Python

本文关键字:ptr 对象 shared 实例化 Python 中从 SWIG      更新时间:2023-10-16

我有一个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处理

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

的段错误:

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>,而只是一个Square又称为BaseClass实例。

是否有可能让test.Square()返回一个共享指针std::shared_ptr<Square> ?

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_ptrstd::weak_ptr)。