1

Python から呼び出すために、いくつかの C++ クラスの周りに薄いラッパーを作成しようとしています。具体的な問題は、virtual以下のコメントが外されている場合、インタープリターを作成しようとするとFoo()クラッシュすることです。この問題を解決するために、このコードを Boost::python、SWIG、または Pyxxx として書き直すことに興味はありません。これは、より大きなシステムからの抜粋です。これらのライブラリのいずれかがこの問題を解決する場合でも、なぜそうなるのか知りたいです。彼らがそれをどのように実装しているか知りたいです。extern "C"拡張モジュールをセットアップしてシステムに型を登録すると、Python インタープリターからの呼び出しは、Python 型のスロットに登録するクラスの静的メンバーを使用するか、または単に持つだけで、問題なく機能します。

メンバーを仮想として宣言すると、それを (Python インタープリターからの呼び出し内で) 呼び出そうとすると、不正なメモリ アクセスでクラッシュが発生します。アクセスされるアドレスは、クラス メンバーをポインターとして出力した場合に得られるオフセットです。従うべき特定のコードがありますが、基本的な質問は次のとおりです。Python によって呼び出される C ランタイム環境の何かが、仮想クラス メンバー関数のディスパッチを台無しにしますか? Python は v2.6.7 で、C++ 拡張機能は GCC 4.2.1 でコンパイルされています。Boost::python がこれをサポートしていることを示唆する関連する質問があります。彼らはそれを直接行っていますか、それともクラス メンバー関数を介してシミュレートしていますか?

// PythonType is a class that inherits from PyTypeObject and fills in defaults ...

extern "C" int initHook(PyObject *self, PyObject *args, PyObject *kwds);
class Foo
{
public:
static PythonType thePyType;
  static void registerType(PyObject *module)
  {
    thePyType.tp_init = initHook;
    PyType_Ready(&thePyType);
    PyModule_AddObject(module, thePyType.tp_name, (PyObject*)&thePyType);
  }

  /*virtual*/ void insert()
  {
    printf("Inserted\n");
  }
};
PythonType Foo::thePyType("Foo",sizeof(Foo));
extern "C" {
  int initHook(PyObject *self, PyObject *args, PyObject *kwds)
  {
    ((Foo*)self)->insert();
  }
}
4

1 に答える 1

0

Let_Me_Be に感謝します。あなたのコメントが私を正しい軌道に乗せました。問題は、Foo オブジェクトのメモリが Python インタープリターによって malloc されていることです。vtable の初期化に依存していないため、他のコードで問題が発生することはありません。最も簡単な解決策は、placement-new を使用して ctor が実際に呼び出され、仮想メンバーが正しく機能することを確認することです。

 int initHook(PyObject *self, PyObject *args, PyObject *kwds)
 {
    new(self) Foo();
    ((Foo*)self)->insert();
 }

On VTable pointers and mallocに、より詳細な Q&A があります。

于 2012-08-02T12:15:02.820 に答える