如何使用shared_ptr和SWIG避免内存泄漏

8
我正在尝试使用boost::shared_ptr,以便我可以在我的Python脚本中使用C++文件I/O流对象。然而,生成的包装器警告我存在内存泄漏问题。
以下是一个展示问题的最小.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?


很高兴看到一个问题有一个完整的、最小化的例子,这使得回答变得容易 :) - Flexo
1个回答

9

你的示例缺少两个部分才能运行析构函数:

  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避免只存在于.i文件中的内容重复:

%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() ) );
}
%}

它一次性声明、定义和封装所有内容。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接