Как избежать утечки памяти с общим ptr и SWIG

Я пытаюсь использовать boost::shared_ptrпозволяет мне использовать объекты потока ввода-вывода файлов c++ в моем скрипте python. Однако сгенерированная обертка предупреждает меня, что это утечка памяти.

вот минимальный .i файл, демонстрирующий проблему:

%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')


%}

вот предупреждение:

In [2]: ptrtest.leak_memory()
swig/python detected a memory leak of type 'ofstream_ptr *', no destructor found.

есть ли способ изменить .i файл, чтобы сообщить интерфейсу, как правильно распоряжаться shared_ptr?

1 ответов


в вашем примере отсутствуют две части, чтобы запустить деструктор:

  1. поскольку SWIG абсолютно ничего не знает о std::ofstream поведение по умолчанию-ничего не делать, кроме передачи непрозрачного дескриптора. См.еще один мой ответ для дальнейшего обсуждения этого вопроса.

    исправление здесь поставить пустую определение std::ofstream в вашем интерфейсном файле, чтобы убедить SWIG, он знает достаточно, чтобы сделать больше, даже если вы не планируете подвергать члены.

  2. SWIG должен увидеть сам typedef-внутри %{ %} Он просто передается прямо в выходной модуль, не используемый в самой обертке.

таким образом, ваш пример становится:

%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')
%}

для дальнейшего использования вы можете избежать дублирования вещей, которые живут только в .я подаю с %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() ) );
}
%}

который объявляет, определяет и обертывает все это одним выстрелом.