当前位置: 首页 > 知识库问答 >
问题:

在使用自定义类型映射时,无法迭代使用SWIG包装的std::vector

闻人飞白
2023-03-14

我使用SWIG类型映射包装一个类,使用SWIG提供的“std_vector.I”包装这个类的std::vector。目标语言是Python。除了我不能在向量上迭代之外,一切似乎都正常。

我创建了一个关于复数的最小示例(仅为方便起见,它与我的真实项目无关)。

这是我想包装的C类:

struct Komplex
{
   Komplex() : real(0.0), imag(0.0) {}
   double real;
   double imag;
};

这是我的SWIG接口文件:

%module myproject
%{ 
#include "komplex.h"
%}

%typemap(typecheck) Komplex& 
{ 
    PyComplex_Check($input) ? 1 : 0; 
}

%typemap(in) Komplex& (Komplex temp) 
{ 
    temp.real = PyComplex_RealAsDouble($input);
    temp.imag = PyComplex_ImagAsDouble($input);
    $1 = &temp; 
}

%typemap(out) Komplex& 
{
    $result = PyComplex_FromDoubles($1->real, $1->imag);
}

// define a vector of the wrapped class:
%include "std_vector.i"
%template(KomplexVector) std::vector<Komplex>;

我可以使用以下Python代码简单地测试typecheck/in/out typemaps:

import myproject

# fill a vector (the "typecheck" and "in" typemaps are used!)
vec = myproject.KomplexVector()
vec.append( complex(1,2) )

# below, the output typemap is used:
print("First attempt:")
for i in xrange(len(vec)):
    print(vec[i])                 # prints: (1+2j)
    assert vec[i] == complex(1,2) # OK

# below, the output typemap is NOT used:
print("Second attempt:")
for k in vec:
    print(k)                 # prints: <Swig Object of type 'Komplex *' at 0x7f0194c6de10>
    assert k == complex(1,2) # fails!

正如您在输出中看到的,在向量上迭代会产生不透明的值:

First attempt:
(1+2j)
Second attempt:
<Swig Object of type 'Komplex *' at 0x7f0194c6de10>
Traceback (most recent call last):
  File "test.py", line 17, in <module>
    assert k == complex(1,2) # fails!
AssertionError
swig/python detected a memory leak of type 'Komplex *', no destructor found.

所以我的问题很简单:我怎样才能让它工作?

我尝试了以下方法:

  • 蛮力,即定义我能想象到的所有可能相关的类型图:
    • 更多输入/输出/varout/...Komplex值/指针/引用/const引用/...
    • std::向量定义in/out/varout/... typemaps

    ...都无济于事。

    完整的源代码(包括Linux/g的一个小构建脚本)可以在这里找到。

    感谢任何帮助!

    编辑:有一些变通方法可以避免缺少正确包装的迭代器,但它们都不漂亮(我认为)。例如,一种可能性是在Python中定义一个自定义迭代器对象,并让SWIG修改Python代码中的迭代器插入方法。

    例如,以下代码将确保向量中k的vec。插入(1,复杂(4,5))将产生预期的行为:

    %pythoncode %{
    class MyVectorIterator(object):
    
        def __init__(self, pointerToVector):
            self.pointerToVector = pointerToVector
            self.index = -1
    
        def next(self):
            self.index += 1
            if self.index < len(self.pointerToVector):
                return self.pointerToVector[self.index]
            else:
                raise StopIteration
    %}
    
    %rename(__cpp_iterator) std::vector<Komplex>::iterator;
    %rename(__cpp_insert) std::vector<Komplex>::insert;
    
    %extend std::vector<Komplex> {
    %pythoncode {
        def iterator(self):
            return MyVectorIterator(self)
        def insert(self, i, x):
            if isinstance(i, int): # "insert" is used as if the vector is a Python list
                _myproject.KomplexVector___cpp_insert(self, self.begin() + i, x)
            else: # "insert" is used as if the vector is a native C++ container
                return _myproject.KomplexVector___cpp_insert(self, i, x)
       }
    }
    
    %include "std_vector.i" 
    %template(KomplexVector) std::vector<Komplex>;
    

    我不会称之为“解决方案”(更不用说“好”的解决方案),但我想它可以作为一种临时解决方案...


共有2个答案

司徒俊良
2023-03-14

我可以通过添加以下行(我在share/swig/python/pyiterators.swg中找到了这个符号)来摆脱STL容器自动生成的包装中的_____函数。我归档

#define SWIGPYTHON_BUILTIN

在此之后,将生成。py文件不再包含____例程,因此Python退回到使用___的方式,如上面其他答案所述。我不知道为什么会这样。(SWIG只是一种尝试

但这可能是一个相当大的黑客,因为我假设这个定义通常只在使用SWIG标志-builtin时设置。但我没有这样做,我只是添加了定义。所以这可能会导致未定义的行为。然而,对我来说,它目前为止还有效...

甘西岭
2023-03-14

现在有点晚了,但让我记录一下我在这里发现的类似问题的解决方案:如果在包含任何SWIG头之前简单地定义SWIG\u NO\u EXPORT\u迭代器\u方法,事情似乎都很好。这是一个相当直截了当的工具,因为它完全禁用了迭代器支持,正如它所说的。对于向量,它仍然允许工作,并以最佳方式工作。然而,当Python退回到在循环中调用\uuuu getitem\uuu时,如果对象没有实现\uu iter\uuu,它就会失败,这正是向量迭代的工作方式。

请注意,SWIG还为其他容器类型生成\uuuu getitem\uuuuu,例如std::liststd::set,但它的实现对它们来说当然是低效的,因此如果使用这些容器,这种解决方法并非没有成本。

 类似资料:
  • 我在目标语言为python的swig接口文件中成功地使用了以下类型映射: 然而,当我将目标语言更改为java时,当我尝试构建swg生成的自动生成的c包装代码时,我会遇到很多编译时错误,即。 等等... 我注意到,在python案例中,粘贴到swig包装器代码中的代码包含,等声明,这些代码来自 它位于 当目标语言为java时,此等效代码不会粘贴到swig包装器代码中。我不完全确定为什么不会发生这种情

  • 如何将此迭代器与泛型类型一起使用?以下是我在“main”函数中尝试的方法: 结果是:<代码>无法从静态上下文引用非静态类项 结果是:<代码>无法从静态上下文引用非静态类项 结果: 编辑: 我调用的是类而不是方法。这项工作: 迭代器it=deq。迭代器(); 我认为,由于iterator()中返回的实例的类型是ListIterator,因此我需要使用该类型声明“it”。

  • 我试图使用一个自定义类作为的键,如下所示: 但是,g给出了以下错误: 我想,我需要告诉C如何散列类,然而,我不太确定如何做。我怎样才能完成这些任务?

  • 我有两个对象,除了date成员外,其他成员都相同。在obj1中,date是java.sql.date,obj2.date是long(纪元)。 我需要编写一个映射器来将obj1映射到obj2。这就是我试图做的: 但是mapperImpl只有自己的日期转换实现: 我得到了: 这种转换的正确方式是什么?

  • 问题内容: 我已经看到了很多类似的问题,但是还没有找到解决我特定问题的方法。我正在尝试SWIGify一些使用std :: function的C ++ 11代码,因此可以在Java应用程序中使用它。 我遇到了这样的共享指针: 并使用shared_ptr指令成功处理了它们,如下所示: 我遇到了像这样的共享指针向量: 并使用如下模板成功处理了它们: 现在我有一个这样的方法: 而且我无法让SWIG正确包装

  • 我正在尝试为C中的以下函数创建JNI包装器: -输入,-输出 -输入,-输出 其中,定义为: 我完全沉浸在Java的SWIG手册中,因为它不只是支持输入参数作为输出类型。我对Python包装器没有任何问题(如下所示)。