在 python 中使用 typemap(out) 调用通过 SWIG 导出的 C++ 类的构造函数,创建一个无效对象

问题描述 投票:0回答:1

这是一个最小的例子。

我有以下 SWIG 接口文件(一体化)

pyhello.i

%module pyhello

%{
  #include <iostream>
  
  // Inline definition of my C++ class
  class MyInt
  {
    public:
      MyInt(int n) : _n(n) {}
      
      static MyInt* create(int n) { return new MyInt(n); }
    
      int get() const { return _n; } 

    private:
      int _n;
  };
%}

%typemap(out) MyInt, MyInt&
{
  std::cout << "%typemap(out) MyInt, MyInt&" << std::endl;
  $result = PyLong_FromLongLong($1.get()); // $1 is an object or a reference
}

%typemap(out) MyInt*
{
  std::cout << "%typemap(out) MyInt*" << std::endl;
  $result = PyLong_FromLongLong($1->get()); // $1 is a pointer
}

// Export MyInt (only public stuff is needed here)
class MyInt
{
  public:
    MyInt(int n);
    
    static MyInt* create(int n);

    int get() const;
};

我使用这两个命令编译它(在 Ubuntu 22.04、g++ 11.4.0、python 3.10.12 和 SWIG 4.2.0 下):

swig -c++ -python -o pyhello_wrap.cpp pyhello.i

g++ -fpic -shared pyhello_wrap.cpp `python3-config --cflags` -o _pyhello.so

然后我运行以下 python 脚本:

from pyhello import *

i1 = MyInt.create(5)
print(type(i1))
print(i1)

i2 = MyInt(6)
print(type(i2))
print(i2)
print(i2.get()) # This one fails

...产生以下输出:

%typemap(out) MyInt*
<class 'int'>
5
%typemap(out) MyInt*
<class 'pyhello.MyInt'>
<pyhello.MyInt; proxy of 6 >
Traceback (most recent call last):
  File "/****/test_pyhello.py", line 10, in <module>
    print(i2.get())
  File "/****/pyhello.py", line 73, in get
    return _pyhello.MyInt_get(self)
TypeError: in method 'MyInt_get', argument 1 of type 'MyInt const *'

我的问题:

  1. 为什么调用构造函数 MyInt 会创建无效的 MyInt Python 中的对象(我们看到类型映射用于获取 整数,然后将整数包装成虚构的 MyInt python 对象)?
  2. 有没有办法为 MyInt 提供类型映射(输出) 'create' 返回本机整数,同时具有以下构造函数 MyInt 不断创建代理对象(就好像没有 类型映射)?

谢谢您的帮助!

python c++ swig typemaps
1个回答
0
投票
  1. 在 SWIG Python 中,构造函数受到与

    get()
    方法相同的类型映射的影响。您拦截它返回的值并将其
    this
    替换为
    int
    对象。结果是一个类似
    int
    的物体。这部分完全在意料之中。

  2. 您只能将类型映射应用于选定的方法:

%typemap(out) MyInt* MyInt::create
{
  std::cout << "%typemap(out) MyInt*" << std::endl;
  $result = PyLong_FromLongLong($1->get()); // $1 is a pointer
}
  1. 不要忘记
%newobject MyInt::create;

如果没有它,你就会造成内存泄漏。

© www.soinside.com 2019 - 2024. All rights reserved.