I'm experiencing an odd issue with a SWIG-generated Python wrapper to a C++ class, wherein I cannot seem to use the standard accessor functions of std::map
when it is wrapped as a std::shared_ptr
type. I managed to produce a MWE that reproduces the odd behavior 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 test script I'm using to test out 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 I try to use the map accessor:
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 of 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 omit the %shared_ptr(TestMap)
declaration from my SWIG interface file and recompile, the map accessor (in test_interface.py) happily works. When I check the type of myTestMap
, it's:
<TestMap.testMap; proxy of <Swig Object of type 'testMap *' at 0x7f8eceb50630> >
So, two questions:
testMap*
), but not when I have a shared_ptr
reference (e.g., std::shared_ptr< testMap > *
)?shared_ptr
for my derived map type?Bonus question: why does SWIG automatically convert testMap*
into a std::shared_ptr<testMap>
type if I declare the existence of a shared_ptr
type for the testMap
type (even if it's not initialized as such?)
First time myTestMap = tm.testMap()
creates an transparent shared_ptr. So myTestMap[1]
is a transparent dereferencing of the shared_ptr with subsequent assignment of the value to the key.
Second time myTestMap = tm.testMap()
creates empty std::map, so myTestMap[1]
is assignment of a value to the the key=1
of the map.
%shared_ptr(testMap)
is semantically similar to %template(testMap) shared_ptr<testMap>
. %template(testMapPtr) shared_ptr<testMap>
will create a new shared_ptr type testMapPtr
, which holds NULL initially (see the default constructor), so testMapPtr[1]
would dereference a NULL value yielding some exception.
Update: %shared_ptr(testMap)
creates a fully transparent shared_ptr initialized with the testMap default constructor.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With