在 Python 中从 SWIG 实例化 shared_ptr 个对象
Instantiate shared_ptr objects from SWIG in Python
我有一个 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))
什么是段错误:
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()
不是 return 一个 std::shared_ptr<BaseClass>
,而是一个 Square
也就是 BaseClass
实例。
是否可以test.Square()
return共享指针std::shared_ptr<Square>
?
SWIG 已经很不错了 support for 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> >
它也应该 'just work' 用于非智能指针参数,但请注意现在 all Python 在该层次结构中创建的实例将是 'smart'.
(如果你有兴趣,我之前也介绍过std::unique_ptr
and std::weak_ptr
)。
我有一个 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))
什么是段错误:
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()
不是 return 一个 std::shared_ptr<BaseClass>
,而是一个 Square
也就是 BaseClass
实例。
是否可以test.Square()
return共享指针std::shared_ptr<Square>
?
SWIG 已经很不错了 support for 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> >
它也应该 'just work' 用于非智能指针参数,但请注意现在 all Python 在该层次结构中创建的实例将是 'smart'.
(如果你有兴趣,我之前也介绍过std::unique_ptr
and std::weak_ptr
)。