1

我正在尝试围绕一些 C++ 类编写一个薄包装器,以便从 Python 调用它们。具体的问题是,如果virtual下面没有注释,那么尝试创建Foo()解释器就会崩溃。我没有兴趣将此代码重写为 Boost::python、SWIG 或 Pyxxx 来解决这个问题 - 这是从一个更大的系统中提取的我想知道它为什么会发生,尽管如果这些库中的任何一个解决了这个问题我很想知道他们是如何实现它的。如果我在系统中设置扩展模块并注册类型,那么来自 Python 解释器的调用可以毫无问题地工作,无论是使用extern "C"类中的静态成员还是仅使用类中的静态成员来在 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 解释器分配。这并没有在我的其他代码中造成问题,因为它不依赖于正在初始化的 vtable。最简单的解决方案是使用placement-new 来确保实际调用ctor,然后虚拟成员正常工作:

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

On VTable pointers 和 malloc有更详细的问答。

于 2012-08-02T12:15:02.820 回答