SWIG封装的向量的向量(C ++到python) - 如何识别内部向量作为代理对象? [英] SWIG wrapped vector of vectors (C++ to python) - how to recognise the inner vector as a proxy object?

查看:1108
本文介绍了SWIG封装的向量的向量(C ++到python) - 如何识别内部向量作为代理对象?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我面临类似的问题, Wrap std :: vector of std :: vectors,C ++ SWIG Python - 但它不只是简单的C ++解析。我在我的C ++代码中有以下内容

 命名空间ns {
typedef unsigned long long uint64_t;
typedef std :: vector< uint64_t>向量;
typedef std :: vector< Vector> VectorOfVectors;

class MyClass {
/// ...

///返回对在C ++ land中分配的内部向量的引用
const VectorOfVectors& ; GetVectors()const;
};
}

并在SWIG包装中

 %module myswig 
// ...
%template(Uint64V)std :: vector< ns :: uint64_t>
%template(VUint64V)std :: vector< std :: vector< ns :: uint64_t> > ;;

所以包装很好,包括类,我可以检索类的向量向量OK:

  import myswig 
m = myswig.MyClass()
v = m.GetVectors()
print v

这给了我:

 < myswig.VUint64V;代理< Swig对象的类型'std :: vector< std :: vector& ns :: uint64_t,std :: allocator< ns :: uint64_t> > > *'at 0x994a050> > 

但是如果我在向量中访问一个元素,我不会得到一个myswig .Uint64V - 这是我的问题。

  x = v [0] 
print x

我希望得到的是:

 < myswig.Uint64V;代理< Swig对象的类型'std :: vector< ns :: uint64_t,std :: allocator< ns :: uint64_t> > *'at 0x994a080> >相反,我得到:



<$>

p $ p> (< Swig对象的类型'ns :: uint64_t *'在0x994a080>,< Swig对象的类型'ns :: uint64_t *'在0x994a098>)

也就是说,向量向量中的索引是给我一个2入口元组,而不是向量的代理



我也收到警告:

  swig / python检测到类型为'ns :: uint64_t *'的内存泄漏,找不到析构函数。 

因为没有为此类型定义析构函数。



任何想法?

解决方案

我与我的同事一起工作,提供一些解决方案。



首先,在SWIG .i文件中,定义这个预处理器变量很重要:

 %{
#define SWIG_PYTHON_EXTRA_NATIVE_CONTAINERS
%}

然后,为了确保从诸如front(),back(),operator []等方法返回的引用实际上映射到内部向量的正确代理类型, typemaps帮助:

  //在pop()
%typemap(out)std :: vector< std ::向量< ns :: uint64_t> > :: value_type {
$ result = SWIG_NewPointerObj(SWIG_as_voidptr(& $ 1),$ descriptor(std :: vector< ns :: uint64_t>),0 | 0)
}

//在前面(),back(),__getitem __()
%typemap(out)std :: vector< std :: vector< ns :: uint64_t> ; > :: value_type& {
$ result = SWIG_NewPointerObj(SWIG_as_voidptr($ 1),$ descriptor(std :: vector< ns :: uint64_t>),0 | 0);
}

我们还发现,如果你想将ns :: uint64_t视为一个python长变量(相当于一个C unsigned long long),然后需要几个其他的类型映射,以确保使用值和引用的向量方法而不是只使用64位整数值。

  //在__getitem __()
%typemap(out)ns :: uint64_t {
$ result = PyLong_FromUnsignedLongLong($ 1);
}
//不使用(但可能有用,只是为了防止)
%typemap(in)ns :: uint64_t {
$ 1 = PyLong_AsUnsignedLongLong($ input);
}
//在pop()
%typemap(out)std :: vector< ns :: uint64_t> :: value_type {
$ result = PyLong_FromUnsignedLongLong($ 1);
}
//在__getitem __(),front(),back()
%typemap(out)std :: vector< ns :: uint64_t> :: value_type& {
$ result = PyLong_FromUnsignedLongLong(* $ 1);
}
//在__setitem __(),append(),new Uint64Vector,push_back(),assign(),resize(),insert()
//这允许python长文字数字用作上述方法的参数。
//注意使用在SWIG包装器函数范围中声明的局部变量
//通过将括号中的变量声明放在开括号{
%typemap(in )std :: vector< ns :: uint64_t> :: value_type& (std :: vector< ns :: uint64_t> :: value_type temp){
temp = PyLong_AsUnsignedLongLong($ input);
$ 1 =& temp;
}

我希望这个解决方案可以帮助未来的人!


I'm facing a similar issue to Wrap std::vector of std::vectors, C++ SWIG Python - but it's not just simple C++ parsing. I have the following in my C++ code

namespace ns {
    typedef unsigned long long uint64_t;
    typedef std::vector<uint64_t> Vector;
    typedef std::vector<Vector> VectorOfVectors;

    class MyClass {
        /// ...

        /// Returns a reference to the internal vector allocated in C++ land
        const VectorOfVectors &GetVectors() const;
    };
}

And in the SWIG wrapper

%module myswig    
// ...
%template(Uint64V) std::vector<ns::uint64_t>;
%template(VUint64V) std::vector<std::vector<ns::uint64_t> >;

So the wrapping works fine, including the class, and I can retrieve the class's vector of vectors OK:

import myswig
m = myswig.MyClass()
v = m.GetVectors()
print v

Which gives me:

<myswig.VUint64V; proxy of <Swig Object of type 'std::vector< std::vector< ns::uint64_t,std::allocator< ns::uint64_t > > > *' at 0x994a050> >

But if I access an element in the vector, I don't get a proxy which is a myswig.Uint64V - and this is my problem.

x = v[0]
print x

What I'd hope to get is:

<myswig.Uint64V; proxy of <Swig Object of type 'std::vector< ns::uint64_t, std::allocator< ns::uint64_t > > *' at 0x994a080> >

Instead, I'm getting:

(<Swig Object of type 'ns::uint64_t *' at 0x994a080>, <Swig Object of type 'ns::uint64_t *' at 0x994a098>) 

That is, the index into the vector of vectors is giving me a 2-entry tuple, and not a proxy to the vector class that I need (so that accessing the internal vector is as easy as accessing other vectors).

I'm also getting the warning:

swig/python detected a memory leak of type 'ns::uint64_t *', no destructor found.

because of course there isn't a destructor defined for this type.

Any ideas?

解决方案

I worked on this with a colleague of mine, and we have managed to come up with some solutions.

First of all, in the SWIG .i file, it's important to define this preprocessor variable:

%{
#   define SWIG_PYTHON_EXTRA_NATIVE_CONTAINERS 
%}

And then, to ensure that the references returned from methods such as front(), back(), operator[], etc are actually mapped to the correct proxy type for the internal vector, the following typemaps help:

// In pop()
%typemap(out) std::vector<std::vector<ns::uint64_t> >::value_type { 
$result = SWIG_NewPointerObj(SWIG_as_voidptr(&$1), $descriptor(std::vector<ns::uint64_t>), 0 |  0 ); 
} 

// In front(), back(), __getitem__()
%typemap(out) std::vector<std::vector<ns::uint64_t> >::value_type & { 
    $result = SWIG_NewPointerObj(SWIG_as_voidptr($1), $descriptor(std::vector<ns::uint64_t>), 0 |  0 ); 
} 

We also discovered that if you want the ns::uint64_t to be treated as a python long variable (equivalent to a C unsigned long long) then a few further typemaps were required to ensure the vector methods using values and references would instead just use 64-bit integer values.

// In __getitem__()
%typemap(out) ns::uint64_t {
    $result = PyLong_FromUnsignedLongLong($1);
}
// Not used (but probably useful to have, just in case)
%typemap(in) ns::uint64_t {
    $1 = PyLong_AsUnsignedLongLong($input);
}
// In pop()
%typemap(out) std::vector<ns::uint64_t>::value_type {
    $result = PyLong_FromUnsignedLongLong($1);
}
// In __getitem__(), front(), back()
%typemap(out) std::vector<ns::uint64_t>::value_type & {
    $result = PyLong_FromUnsignedLongLong(*$1);
}
// In __setitem__(), append(), new Uint64Vector, push_back(), assign(), resize(), insert()
// This allows a python long literal number to be used as a parameter to the above methods. 
// Note the use of a local variable declared at the SWIG wrapper function scope,
// by placing the variable declaration in parentheses () prior to the open brace {
%typemap(in) std::vector<ns::uint64_t>::value_type & (std::vector<ns::uint64_t>::value_type temp) {
    temp = PyLong_AsUnsignedLongLong($input);
    $1 = &temp;
}

I hope this solution helps people in future!

这篇关于SWIG封装的向量的向量(C ++到python) - 如何识别内部向量作为代理对象?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆