2017-07-31 192 views
5

我遇到了一个SWIG生成的Python封装到C++类的奇怪问题,其中我似乎无法使用标准存取函数std::map,当它被封装为std::shared_ptr类型时。我设法产生了一个能够再现我所观察到的奇怪行为的MWE。SWIG:使用std :: map访问器与shared_ptr?

TestMap.h

#include <iostream> 
#include <map> 
#include <memory> 

class fooType{ 
    public: 
    fooType() { }; 
    ~fooType() { }; 
    void printFoo() { std::cerr << "FOO!" << std::endl; } 
    static std::shared_ptr<fooType> make_shared() { 
     return std::shared_ptr<fooType>(new fooType()); 
    } 
}; 

class testMap : public std::map<int, std::shared_ptr<fooType> > { 
    public: 
    void printBar() { std::cerr << "bar." << std::endl; } 
}; 

然后我痛饮接口文件:

TestMap.i

%module TestMap 

%include <std_map.i> 
%include <std_shared_ptr.i> 

%{ 
#include "TestMap.h" 
%} 

%shared_ptr(fooType); 
%shared_ptr(testMap); 
%shared_ptr(std::map<int, std::shared_ptr<fooType> >); 

%template(fooMap) std::map< int, std::shared_ptr<fooType> >; 

%include "TestMap.h" 

最后,我使用的测试脚本来测试出界面:

test_interface.py

import TestMap as tm 

ft = tm.fooType.make_shared() 
myTestMap = tm.testMap() 

myTestMap[1] = ft 

至于写,我得到以下错误,当我尝试使用地图访问:

Traceback (most recent call last): 
    File "test_interface.py", line 9, in <module> 
    myTestMap[1] = ft 
    File "/home/sskutnik/tstSWIG/TestMap.py", line 217, in __setitem__ 
    return _TestMap.fooMap___setitem__(self, *args) 
NotImplementedError: Wrong number or type of arguments for overloaded function 'fooMap___setitem__'. 
    Possible C/C++ prototypes are: 
    std::map< int,std::shared_ptr<fooType> >::__setitem__(std::map< int,std::shared_ptr<fooType> >::key_type const &) 
    std::map< int,std::shared_ptr<fooType> >::__setitem__(std::map< int,std::shared_ptr<fooType> >::key_type const &,std::map< int,std::shared_ptr<fooType> >::mapped_type const & 

当我检查的ftmyTestMap型两种,分别为std::shared_ptr参考号:

<TestMap.fooType; proxy of <Swig Object of type 'std::shared_ptr<fooType> *' at 0x7fa812e80a80> > 
<TestMap.testMap; proxy of <Swig Object of type 'std::shared_ptr<testMap> *' at 0x7fa812e80c90> > 

现在的奇数部分 - 如果我省略了SWIFT接口文件中的%shared_ptr(TestMap)声明并重新编译,映射存取器(位于test_interface.py)很高兴地工作。当我检查的myTestMap类型,它是:

<TestMap.testMap; proxy of <Swig Object of type 'testMap *' at 0x7f8eceb50630> > 

于是,两个问题:

  1. 为什么我访问函数调用正常工作时,我有一个痛饮对象的指针引用(testMap*),而不是在我有一个shared_ptr参考(例如,std::shared_ptr<testMap> *)?
  2. 我如何解决这个问题,因为我需要一个shared_ptr为我的派生地图类型?

奖金的问题:为什么SWIG自动转换testMap*std::shared_ptr<testMap>类型,如果我宣布一个shared_ptr类型的testMap类型的存在

回答

1

第一次(即使它不是初始化为这样的?) myTestMap = tm.testMap()创建一个透明的shared_ptr。因此myTestMap[1]是shared_ptr的透明解引用,随后将值赋给键。
第二次myTestMap = tm.testMap()创建空的std :: map,因此myTestMap[1]将赋值给映射的key=1

%shared_ptr(testMap)在语义上与%template(testMap) shared_ptr<testMap>相似。%template(testMapPtr) shared_ptr<testMap>将创建一个新的shared_ptr类型testMapPtr,它最初保留NULL(请参阅default constructor),因此testMapPtr[1]会取消引用NULL值,从而产生一些异常。
更新:%shared_ptr(testMap)创建一个完全透明的shared_ptr,用testMap默认构造函数初始化。

+1

至于“Bonus question”:'%shared_ptr(testMap)'与%template(testMap)shared_ptr '相同。使用'%template(testMapPtr)shared_ptr '来避免testMap语义的这种变化。 – luart

+0

这个解释对我来说很有意义。我注意到的是,即使我创建了一个方法来为testMap显式创建一个非空的shared_ptr,我也遇到了同样的问题。然而,我注意到当我从共享指针模板(例如'%template(testMapPtr)std :: shared_ptr '中分离出testMap的定义时,我反而得到了项目赋值操作符(有用)的错误不支持 将智能指针模板从基类中分离出来,然后在需要智能指针类型时使用备用函数工作,谢谢! –

+1

欢迎您,欢迎回答有用!我的解释做了一个小小的修改:'%template(testMapPtr)shared_ptr '导致最初为空testMapPtr共享指针,但'%shared_ptr(testMap)'实际上创建了一个透明的shared_ptr,它已经用'testMap'实例初始化我会将其添加到答案中。 – luart

相关问题