SWIG: Using std :: map accessors with shared_ptr?

I had a strange problem with a SWIG-generated Python shell for a C ++ class, in which I cannot use the standard std::map access functions when it is wrapped as a std::shared_ptr . I managed to create an MWE that reproduces the odd behavior that I am observing.

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

And then my SWIG interface file:

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" 

Finally, the script test that I use to test the interface:

test_interface.py

 import TestMap as tm ft = tm.fooType.make_shared() myTestMap = tm.testMap() myTestMap[1] = ft 

As written, I get the following error when trying to use a card accessory:

 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 & 

When I check the type of ft and myTestMap , both are std::shared_ptr references to their respective classes:

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

Now for the odd part - if I omitted the %shared_ptr(TestMap) from my SWIG interface file and recompiled, the map accessory happily works for it (in test_interface.py ). When I check the myTestMap type, this is:

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

So, two questions:

  • Why does my access request work correctly when I have a reference to a pointer to a SWIG object ( testMap* ), but not when I have a shared_ptr link (for example, std::shared_ptr< testMap > * )?
  • How do I get around this, given that I need shared_ptr for my derived map type?

Bonus question: why does SWIG automatically convert testMap* to type std::shared_ptr<testMap> if I declare the existence of shared_ptr for type testMap (even if it is not initialized as such?)

+5
source share
1 answer

The first time myTestMap = tm.testMap() a transparent shared_ptr is created. Thus, myTestMap[1] is a transparent dereferencing of shared_ptr and then assigning a value to the key.
The second time myTestMap = tm.testMap() creates an empty std :: map, so myTestMap[1] is the assignment key=1 map to the value key=1 .

%shared_ptr(testMap) semantically similar to %template(testMap) shared_ptr<testMap> . %template(testMapPtr) shared_ptr<testMap> will create a new type shared_ptr testMapPtr , which first contains NULL (see the default constructor ), so testMapPtr[1] will dereference NULL gives some exception.
Update: %shared_ptr(testMap) creates a fully transparent shared_ptr initialized by the default constructor testMap.

+1
source

Source: https://habr.com/ru/post/1270395/


All Articles