如何正确地使用SWIG将std::vector<std::size_t>包装为Python?使用std::size_t时出现的问题。

11

我正在尝试让std::vector<std::size_t>在SWIG中正常工作。我需要为C++库提供Python接口。原生类型和对象的std::vector可以正常工作,但是std::size_t存在问题。

我在Github上提供了一个最小可行示例 here

主要问题

问题在于std::size_t无法被识别,因此std::vector<std::size_t>被视为std::vector< int,std::allocator< int > > *。当我尝试指定模板时,会出现以下情况。

使用%template(VecSize) std::vector<std::size_t>;将会得到:

swig -c++ -python c_swig_vec_std_size.i
:0: Warning(490): Fragment 'SWIG_AsVal_std_size_t' not found.
:0: Warning(490): Fragment 'SWIG_From_std_size_t' not found.
g++ -fpic -c c_swig_vec_std_size_wrap.cxx -I/public/users/paul/dev/software/Python-2.7.11/Include -I/public/users/paul/dev/software/Python-2.7.11
c_swig_vec_std_size_wrap.cxx: In static member function ‘static int swig::traits_asval<long unsigned int>::asval(PyObject*, swig::traits_asval::value_type*)’:
c_swig_vec_std_size_wrap.cxx:4289: error: ‘SWIG_AsVal_std_size_t’ was not declared in this scope
c_swig_vec_std_size_wrap.cxx: In static member function ‘static PyObject* swig::traits_from<long unsigned int>::from(const swig::traits_from::value_type&)’:
c_swig_vec_std_size_wrap.cxx:4295: error: ‘SWIG_From_std_size_t’ was not declared in this scope
make: *** [c] Error 1

最小示例

C++示例类

以下类足以展示我所需的功能。包含std::vector<int>是为了展示预期的行为。

class_vec_std_size.hpp

#ifndef STD_SIZE_VEC
#define STD_SIZE_VEC

#include <vector>

class StdSizeVec{

public:
  StdSizeVec(){
    _myVec = std::vector<std::size_t>();
    _myVec.push_back(1);
    _myVec.push_back(2);

    _myInts = std::vector<int>();
    _myInts.push_back(1);
    _myInts.push_back(2);
  }

  ~StdSizeVec(){
    _myVec.clear();
  }

  inline std::vector<std::size_t> getValues(){
    return _myVec;
  }

  inline std::vector<int> getInts(){
    return _myInts;
  }

private:
  std::vector<std::size_t> _myVec;
  std::vector<int> _myInts;
};
#endif

不同的界面尝试

a_swig_vec_std_size.i

%module a_swig_vec_std_size
%{
#include "class_vec_std_size.hpp"
%}
%include "class_vec_std_size.hpp"

输出

[paul@login-0-0 stack_swig]$ python
Python 2.7.11 (default, May  7 2016, 23:37:19) 
[GCC 4.4.7 20120313 (Red Hat 4.4.7-16)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from a_swig_vec_std_size import StdSizeVec
>>> ssv = StdSizeVec()
>>> vals = ssv.getValues()
>>> vals
<Swig Object of type 'std::vector< std::size_t > *' at 0x2ad7047be330>
>>> ints = ssv.getInts()
>>> ints
<Swig Object of type 'std::vector< int > *' at 0x2ad7047be780>
>>> exit()
swig/python detected a memory leak of type 'std::vector< int > *', no destructor found.
swig/python detected a memory leak of type 'std::vector< std::size_t > *', no destructor found.
[paul@login-0-0 stack_swig]$

这是基本的天真方法。在Python中指针并不实用,并且存在无法向接口用户公开的内存泄漏消息。

b_swig_vec_std_size.i

%module b_swig_vec_std_size
%{
#include "class_vec_std_size.hpp"
%}
%include "std_vector.i"
%include "class_vec_std_size.hpp"

输出

[paul@login-0-0 stack_swig]$ python
Python 2.7.11 (default, May  7 2016, 23:37:19) 
[GCC 4.4.7 20120313 (Red Hat 4.4.7-16)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from b_swig_vec_std_size import StdSizeVec
>>> ssv = StdSizeVec()
>>> vals = ssv.getValues()
>>> vals
<Swig Object of type 'std::vector< std::size_t,std::allocator< std::size_t > > *' at 0x2aee17458330>
>>> ints = ssv.getInts()
>>> ints
<Swig Object of type 'std::vector< int,std::allocator< int > > *' at 0x2aee17458930>
>>> exit()
swig/python detected a memory leak of type 'std::vector< int,std::allocator< int > > *', no destructor found.
swig/python detected a memory leak of type 'std::vector< std::size_t,std::allocator< std::size_t > > *', no destructor found.

使用正确的“std_vector.i”,SWIG对于向量和分配器有更多了解,但是这些指针对Python客户端代码没有用处,并且会出现内存泄漏错误消息。

c_swig_vec_std_size.i

这个接口使用了正确的%template指令,如this answer。在这里,SWIG无法将std::size_t理解为一个模板参数。

%module c_swig_vec_std_size
%{
#include "class_vec_std_size.hpp"
%}
%include "std_vector.i"
%template(VecInt) std::vector<int>;

// Does not compile
//%template(VecSize) std::vector<std::size_t>;
//
// Gives the following errors
//swig -c++ -python c_swig_vec_std_size.i
// :0: Warning(490): Fragment 'SWIG_AsVal_std_size_t' not found.
// :0: Warning(490): Fragment 'SWIG_From_std_size_t' not found.
// g++ -fpic -c c_swig_vec_std_size_wrap.cxx -I/public/users/paul/dev/software/Python-2.7.11/Include -I/public/users/paul/dev/software/Python-2.7.11
// c_swig_vec_std_size_wrap.cxx: In static member function ‘static int swig::traits_asval<long unsigned int>::asval(PyObject*, swig::traits_asval::value_type*)’:
// c_swig_vec_std_size_wrap.cxx:4289: error: ‘SWIG_AsVal_std_size_t’ was not declared in this scope
// c_swig_vec_std_size_wrap.cxx: In static member function ‘static PyObject* swig::traits_from<long unsigned int>::from(const swig::traits_from::value_type&)’:
// c_swig_vec_std_size_wrap.cxx:4295: error: ‘SWIG_From_std_size_t’ was not declared in this scope
// make: *** [c] Error 1

//The following compiles but does not work
%template(VecSize) std::vector<size_t>;

%include "class_vec_std_size.hpp"

输出

[paul@login-0-0 stack_swig]$ python
Python 2.7.11 (default, May  7 2016, 23:37:19) 
[GCC 4.4.7 20120313 (Red Hat 4.4.7-16)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from c_swig_vec_std_size import StdSizeVec
>>> ssv = StdSizeVec()
>>> vals = ssv.getValues()
>>> vals
<Swig Object of type 'std::vector< std::size_t,std::allocator< std::size_t > > *' at 0x2b286104bd80>
>>> ints = ssv.getInts()
>>> ints
(1, 2)
>>> exit()
swig/python detected a memory leak of type 'std::vector< std::size_t,std::allocator< std::size_t > > *', no destructor found.

现在std :: vector<int>正常工作,但是SWIG的%template(VecSize) std::vector<size_t>;(没有带有std :: )不能胜任。

一些互联网挖掘

我发现了一些帖子提供了一些线索。

this这样的感觉,我找到了一个2006年具有相同问题的帖子

std :: vector :: size_type被包装为指针而不是整数链接提供了一些有用的信息,但问题并非完全相同。

我发现这个primitives.i来自magnum.fe项目,但是仅仅想着导入primitives.i并不能让我成功。
之后,我尝试按照他们的方式实现SWIG_AsVal_std_size_tSWIG_From_std_size_t,但是没有成功。

手动编写std_size_t.i

%fragment("SWIG_From_std_size_t", "header", fragment=SWIG_From_frag(std::size_t))
{
  SWIGINTERNINLINE PyObject * SWIG_From_std_size_t(std::size_t value)
  {
    return PyInt_FromSize_t(value);
  }
}


%fragment("SWIG_AsVal_std_size_t", "header")
{

SWIGINTERNINLINE bool SWIG_AsVal_std_size_t(PyObject* in, std::size_t& value)
{

  // Get integer type
  if(PyInt_Check(in)){
    long unsigned int long_uint = PyLong_AsLong(in);
    value = static_cast<std::size_t>(long_uint);
    return true;
  }else{
    return false;
  }

}
}

%fragment(SWIG_From_frag(std::size_t));
%fragment("SWIG_AsVal_std_size_t");

这个被导入了d_swig_vec_std_size.i,但是它无法编译。
%module d_swig_vec_std_size
%{
#include "class_vec_std_size.hpp"
%}
%include "std_vector.i"
%template(VecInt) std::vector<int>;

%include "std_size_t.i"
%template(VecSize) std::vector<std::size_t>;

%include "class_vec_std_size.hpp"

这里我得到了这个。

swig -c++ -python d_swig_vec_std_size.i
g++ -fpic -c d_swig_vec_std_size_wrap.cxx -I/public/users/paul/dev/software/Python-2.7.11/Include -I/public/users/paul/dev/software/Python-2.7.11
d_swig_vec_std_size_wrap.cxx: In static member function ‘static int swig::traits_asval<long unsigned int>::asval(PyObject*, swig::traits_asval::value_type*)’:
d_swig_vec_std_size_wrap.cxx:4311: error: invalid initialization of reference of type ‘size_t&’ from expression of type ‘swig::traits_asval::value_type*’
d_swig_vec_std_size_wrap.cxx:4288: error: in passing argument 2 of ‘bool SWIG_AsVal_std_size_t(PyObject*, size_t&)’
make: *** [d] Error 1

makefile

PYTHON=/public/users/paul/dev/software/Python-2.7.11

all: a b c d

a:
    swig -c++ -python a_swig_vec_std_size.i
    g++ -fpic -c a_swig_vec_std_size_wrap.cxx -I${PYTHON}/Include -I${PYTHON}
    g++ -g -fpic -shared a_swig_vec_std_size_wrap.o -o _a_swig_vec_std_size.so

b:
    swig -c++ -python b_swig_vec_std_size.i
    g++ -fpic -c b_swig_vec_std_size_wrap.cxx -I${PYTHON}/Include -I${PYTHON}
    g++ -g -fpic -shared b_swig_vec_std_size_wrap.o -o _b_swig_vec_std_size.so

c:
    swig -c++ -python c_swig_vec_std_size.i
    g++ -fpic -c c_swig_vec_std_size_wrap.cxx -I${PYTHON}/Include -I${PYTHON}
    g++ -g -fpic -shared c_swig_vec_std_size_wrap.o -o _c_swig_vec_std_size.so

d:
    swig -c++ -python d_swig_vec_std_size.i
    g++ -fpic -c d_swig_vec_std_size_wrap.cxx -I${PYTHON}/Include -I${PYTHON}
    g++ -g -fpic -shared d_swig_vec_std_size_wrap.o -o _d_swig_vec_std_size.so


clean: clean_a clean_b clean_c clean_d

clean_a:
    rm a_swig_vec_std_size_wrap.cxx a_swig_vec_std_size.py a_swig_vec_std_size_wrap.o _a_swig_vec_std_size.so

clean_b:
    rm b_swig_vec_std_size_wrap.cxx b_swig_vec_std_size.py b_swig_vec_std_size_wrap.o _b_swig_vec_std_size.so

clean_c:
    rm c_swig_vec_std_size_wrap.cxx c_swig_vec_std_size.py c_swig_vec_std_size_wrap.o _c_swig_vec_std_size.so

clean_d:
    rm d_swig_vec_std_size_wrap.cxx d_swig_vec_std_size.py d_swig_vec_std_size_wrap.o _d_swig_vec_std_size.so

程序版本

python version: Python 2.7.11
g++ version: g++ (GCC) 4.4.7
swig version: SWIG Version 1.3.40

使用更新的swig版本(swig-3.0.10)对我来说结果相同。

概要

我怀疑答案可能与接口d有关,但到目前为止我没有成功。可能存在一个问题,即std::size_t的实现方式因架构不同而不同,而不是具有固定的大小。无论如何,我希望SWIG能够处理它。我有什么遗漏吗?我想找到一种解决方案,不需要对C++库进行更改(例如将std::size_t封装在struct中或使用int代替)。

尝试Jens Monk的解决方案

namespace std {
    %template(VecSize) vector<size_t>;
}

我得到了这个:
[paul@login-0-0 stack_swig]$ make clean
rm a_swig_vec_std_size_wrap.cxx a_swig_vec_std_size.py a_swig_vec_std_size_wrap.o _a_swig_vec_std_size.so
rm b_swig_vec_std_size_wrap.cxx b_swig_vec_std_size.py b_swig_vec_std_size_wrap.o _b_swig_vec_std_size.so
rm c_swig_vec_std_size_wrap.cxx c_swig_vec_std_size.py c_swig_vec_std_size_wrap.o _c_swig_vec_std_size.so
rm d_swig_vec_std_size_wrap.cxx d_swig_vec_std_size.py d_swig_vec_std_size_wrap.o _d_swig_vec_std_size.so
[paul@login-0-0 stack_swig]$ make
swig -c++ -python a_swig_vec_std_size.i
g++ -fpic -c a_swig_vec_std_size_wrap.cxx -I/public/users/paul/dev/software/Python-2.7.11/Include -I/public/users/paul/dev/software/Python-2.7.11
g++ -g -fpic -shared a_swig_vec_std_size_wrap.o -o _a_swig_vec_std_size.so
swig -c++ -python b_swig_vec_std_size.i
g++ -fpic -c b_swig_vec_std_size_wrap.cxx -I/public/users/paul/dev/software/Python-2.7.11/Include -I/public/users/paul/dev/software/Python-2.7.11
g++ -g -fpic -shared b_swig_vec_std_size_wrap.o -o _b_swig_vec_std_size.so
swig -c++ -python c_swig_vec_std_size.i
g++ -fpic -c c_swig_vec_std_size_wrap.cxx -I/public/users/paul/dev/software/Python-2.7.11/Include -I/public/users/paul/dev/software/Python-2.7.11
g++ -g -fpic -shared c_swig_vec_std_size_wrap.o -o _c_swig_vec_std_size.so
swig -c++ -python -I/public/users/paul/dev/software/swig-3.0.10  d_swig_vec_std_size.i
g++ -fpic -c d_swig_vec_std_size_wrap.cxx -I/public/users/paul/dev/software/Python-2.7.11/Include -I/public/users/paul/dev/software/Python-2.7.11
g++ -g -fpic -shared d_swig_vec_std_size_wrap.o -o _d_swig_vec_std_size.so
[paul@login-0-0 stack_swig]$ python
Python 2.7.11 (default, May  7 2016, 23:37:19) 
[GCC 4.4.7 20120313 (Red Hat 4.4.7-16)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from d_swig_vec_std_size import StdSizeVec
>>> ssv = StdSizeVec()
>>> vals = ssv.getValues()
>>> vals
<Swig Object of type 'std::vector< std::size_t,std::allocator< std::size_t > > *' at 0x2aba7dd8bd80>
>>> ints - ssv.getInts()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'ints' is not defined
>>> ints = ssv.getInts()
>>> ints
(1, 2)
>>> exit()
swig/python detected a memory leak of type 'std::vector< std::size_t,std::allocator< std::size_t > > *', no destructor found.
[paul@login-0-0 stack_swig]$ cat d_swig_vec_std_size.i 
%module d_swig_vec_std_size
%{
#include "class_vec_std_size.hpp"
%}
%include "std_vector.i"
%template(VecInt) std::vector<int>;

%include "std_size_t.i"

namespace std {
  %template(VecSize) vector<size_t>;
}


%include "class_vec_std_size.hpp"
2个回答

3

看起来很有帮助。您如何指定std命名空间并在向量模板中使用它? - pbible

3

按照以下方式实例化您的模板

namespace std {
  %template(VecSize) vector<size_t>;
}

这个更改对于我这个环境(使用SWIG 3.0.2,g++ 4.9.2和Python 2.7.9)来说可以直接使用。我已经在您的项目中更改了d_swig_vec_std_size.i文件,并在您的makefile中将包含路径更改为/ usr / include / python2.7

%module d_swig_vec_std_size
%{
#include "class_vec_std_size.hpp"
%}
%include "std_vector.i"
%template(VecInt) std::vector<int>;

%include "std_size_t.i"

namespace std {
  %template(VecSize) vector<size_t>;
}


%include "class_vec_std_size.hpp"

我运气不佳。你能贴出你的整个.i文件吗?我尝试了我安装的Swig 3.0.10,但仍然没有效果。 - pbible
我尝试了Swig 2.0.12版本,这个版本也可以正常工作。如果你觉得需要的话,我可以尝试另一个编译器版本。 - Jens Munk
非常感谢您的时间。我尝试了解决方案并编辑了问题以显示输出。不幸的是,它对我没有起作用。它可以编译,但输出仍然与预期不符。我也在我的 Mac 上尝试过。我想知道这是否与我安装 swig 的方式有关。如果您无法重现错误,则可能存在更大的问题。 - pbible
在我的Mac上,我从源代码安装了swig 3.0.10,只需使用./configure、make和make install命令。但是没有成功。您认为swig是否需要任何特殊的构建标志来支持std::size_t?我正在使用GCC 4.2.1兼容的Apple LLVM 5.0(clang-500.0.68)和Python 2.7.5。 - pbible
可能是因为 SWIG 在错误的位置解析标准头文件。Macintosh 允许在任何地方安装,破坏了结构。您需要使用编译器。 - Jens Munk
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接