4

私はC++ライブラリと一緒にPythonモジュールを開発しています。C ++コードには、次のようにヒープオブジェクトを返す関数があります。

MyClass* func()
{
  MyClass* myclass = new MyClass();
  return myclass;
}

しかし、Python側でこの関数を使用すると、返されたオブジェクトを削除できません。

myclass = func()
del myclass # still remains in memory

Pythonコードで返されたオブジェクトを削除する方法を教えてもらえますか?

このメモリリークを回避できるように、戻り値のタイプをMyClass*からMyClassに変更できます。しかし、C ++ライブラリはすでに別の場所で使用されているため、C++コードには触れたくありません。

4

1 に答える 1

8

SWIG のドキュメントのセクション11.2%newobjectにあるおよび%typemap(newfree)ディレクティブを参照してください。

ドキュメントから引用:

一部のアプリケーションでよくある問題は、オブジェクトの適切な所有権を管理することです。たとえば、次のような関数を考えてみましょう。

Foo *blah() {
   Foo *f = new Foo();
   return f;
}

関数 blah() をラップすると、SWIG は戻り値が新しく割り当てられたオブジェクトであることを認識しません。その結果、拡張モジュールによってメモリ リークが発生する可能性があります (SWIG は保守的であり、返されたオブジェクトが新しく作成されたことを確実に認識しない限り、オブジェクトを削除しません)。

これを修正するには、%newobject ディレクティブを使用してコード ジェネレーターに追加のヒントを提供します。例えば:

%newobject blah;
Foo *blah();

%newobject は、%rename および %exception とまったく同じように機能します。つまり、以前と同様に、クラス メンバーとパラメーター化された宣言にアタッチできます。例えば:

%newobject ::blah();                   // Only applies to global blah
%newobject Object::blah(int,double);   // Only blah(int,double) in Object
%newobject *::copy;                    // Copy method in all classes
...

%newobject が提供されると、多くの言語モジュールが戻り値の所有権を取得します。これにより、使用されなくなった値を自動的にガベージ コレクションできます。ただし、これはターゲット言語に完全に依存します (言語モジュールは、%newobject ディレクティブを無視することも選択できます)。

%newobject と密接に関連しているのは、特別な typemap です。「newfree」タイプマップを使用して、新しく割り当てられた戻り値の割り当てを解除できます。%newobject が適用されたメソッドでのみ使用でき、文字列の結果をクリーンアップするために一般的に使用されます。例えば:

%typemap(newfree) char * "free($1);";
...
%newobject strdup;
...
char *strdup(const char *s);

この場合、関数の結果はターゲット言語の文字列になります。この文字列は元の結果のコピーであるため、strdup() によって返されるデータは不要になります。この例の「newfree」タイプマップは、単にこのメモリを解放します。

于 2013-03-03T15:02:22.867 に答える