2017-07-31 117 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