I'm trying to use boost::shared_ptr
's to allow for me to use c++ file I/O stream objects in my python script. However, the generated wrapper warns me that it is leaking memory.
Here's a minimal .i
file exhibiting the problem:
%module ptrtest
%include "boost_shared_ptr.i"
%include "std_string.i"
%shared_ptr( std::ofstream )
%{
#include <fstream>
#include <boost/shared_ptr.hpp>
typedef boost::shared_ptr< std::ofstream > ofstream_ptr;
ofstream_ptr mk_out(const std::string& fname ){
return ofstream_ptr( new std::ofstream( fname.c_str() ) );
}
%}
ofstream_ptr mk_out(const std::string& fname );
%pythoncode %{
def leak_memory():
''' demonstration function -- when I call
this, I get a warning about memory leaks
''''
ostr=mk_out('/tmp/dont_do_this.txt')
%}
Here's the warning:
In [2]: ptrtest.leak_memory()
swig/python detected a memory leak of type 'ofstream_ptr *', no destructor found.
Is there a way to modify the .i
file to tell the interface how to dispose of the shared_ptr properly?
Cyclic reference problem with shared_ptr The problem with shared_ptr is that if there is a ring, or cycle of an objects that have shared_ptr to each other, they keep each other alive - they won't get deleted as they are holding each other (i.e, still has a shared_ptr pointing to them) leading to memory leak.
Your example is missing two parts to get the destructor to run:
Since SWIG knows absolutely nothing about std::ofstream
the default behaviour is to do nothing beyond pass an opaque handle around. See another answer of mine for a further discussion of this.
The fix here is to supply an empty definition for std::ofstream
in your interface file to convince SWIG it knows enough to do more, even if you don't plan on exposing any members.
SWIG needs to see the typedef itself - inside the %{ %}
it just gets passed straight to the output module, not used in the wraping itself.
Thus your example becomes:
%module ptrtest
%include "boost_shared_ptr.i"
%include "std_string.i"
%shared_ptr( std::ofstream )
namespace std {
class ofstream {
};
}
%{
#include <fstream>
#include <boost/shared_ptr.hpp>
typedef boost::shared_ptr< std::ofstream > ofstream_ptr;
ofstream_ptr mk_out(const std::string& fname ){
return ofstream_ptr( new std::ofstream( fname.c_str() ) );
}
%}
typedef boost::shared_ptr< std::ofstream > ofstream_ptr;
ofstream_ptr mk_out(const std::string& fname );
%pythoncode %{
def leak_memory():
ostr=mk_out('/tmp/dont_do_this.txt')
%}
For future reference you can avoid duplication of stuff that lives only in the .i file with %inline
:
%inline %{
typedef boost::shared_ptr< std::ofstream > ofstream_ptr;
ofstream_ptr mk_out(const std::string& fname ){
return ofstream_ptr( new std::ofstream( fname.c_str() ) );
}
%}
Which declares, defines and wraps it all in one shot.
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