2017-07-31 6 views
5

std::shared_ptrタイプとしてラップされているときに、std::mapの標準アクセサー関数を使用できないような、C++クラスへのSWIG生成のPythonラッパーに関する奇妙な問題が発生しています。私は観察している奇妙な行動を再現するMWEを作り出しました。SWIG:shared_ptrでstd :: mapアクセサを使用しますか?

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; } 
}; 

そして、私のSWIGインタフェースファイル:

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" 

最後に、私が使用しているテストスクリプトをテストしますインターフェイス外:

AS-書か

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> > 

今、奇妙な部分について - SWIGインターフェイスファイルから%shared_ptr(TestMap)宣言を省略して再コンパイルすると、マップアクセサ(test_interface.py)がうまく動作します。私はmyTestMapの種類を確認すると、それはです:

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

ので、二つの質問:

  1. はなぜ私のアクセサは、ときに私はSWIGオブジェクトのポインタ参照(testMap*)を持っている場合、正しく作業を呼び出すのではなく、私はshared_ptrのリファレンスを持っています(例えばstd::shared_ptr<testMap> *)?
  2. 派生したマップタイプにshared_ptrが必要な場合、これを回避するにはどうすればよいですか?

ボーナス質問:私はtestMapタイプにshared_ptrタイプが存在することを宣言した場合、なぜSWIGが自動的に(それはのような初期化されていないだ場合でも?)std::shared_ptr<testMap>型に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>は、最初にNULLを保持する新しいshared_ptrタイプtestMapPtrを作成します(default constructorを参照)。したがって、testMapPtr[1]はNULL値を逆参照して例外を生成します。
更新:%shared_ptr(testMap)は、完全に透過なshared_ptrを、testMapのデフォルトコンストラクタで初期化して作成します。

+1

「ボーナスの質問」: '%shared_ptr(testMap)'は '%template(testMap)shared_ptr 'と同じです。そのようなtestMapセマンティクスの変更を避けるには、 '%template(testMapPtr)shared_ptr 'を使用してください。 – luart

+0

この説明はほとんどの場合私には意味があります。私が気づいたことは、たとえtestMapのためのnull以外のshared_ptrを明示的に作成するメソッドを作成したとしても、私は同じ問題があることです。 しかし、私は、共有ポインタテンプレート(例えば '%template(testMapPtr)std :: shared_ptr ')からtestMapの定義を除外したとき、代わりにアイテム割り当て演算子が スマートポインタテンプレートを基底クラスから分離し、スマートポインタ型を持たなければならないときに代替関数を使用しています。ありがとう! –

+1

あなたは歓迎です。 '%template(testMapPtr)shared_ptr 'は最初は空の 'testMapPtr'共有ポインタを返しますが、'%shared_ptr(testMap) 'は実際に' testMap'インスタンスで既に初期化されている透過shared_ptrを作成します私はそれを答えに加えます。 – luart

関連する問題