在 PyObject_NEW 创建时初始化非平凡的 class 成员
Initialize nontrivial class members when created by PyObject_NEW
我有一个 Python object 引用 C++ object。
Header:
#define PY_SSIZE_T_CLEAN
#include <Python.h>
#include <structmember.h>
typedef struct {
PyObject_HEAD
FrameBuffer frame_buffer;
} PyFrameBuffer;
extern PyTypeObject PyFrameBuffer_type;
extern PyObject* PyFrameBuffer_NEW(size_t width, size_t height);
C++ FrameBuffer
class 如下:
class FrameBuffer {
public:
explicit FrameBuffer(const size_t width, const size_t height);
// ...
private:
size_t m_width;
size_t m_height;
std::vector<Pixel> m_pixels;
};
Pixel
是几个普通类型元素的简单 class。
PyFrameBuffer_NEW()
函数如下:
PyObject* PyFrameBuffer_NEW(size_t width, size_t height)
{
auto* fb = (PyFrameBuffer*) PyObject_NEW(PyFrameBuffer, &PyFrameBuffer_type);
if (fb != nullptr)
{
fb->frame_buffer = FrameBuffer(width, height);
}
return (PyObject*) fb;
}
此代码崩溃:
fb->frame_buffer
分配了未定义的值(fb->frame_buffer.m_pixels.size()
未定义)。
在 fb->frame_buffer
赋值期间,m_pixels
.
中有未定义数量的 Pixel
的重新分配
所以,它崩溃了。
此代码似乎 有效:
/// ...
if (fb != nullptr)
{
FrameBuffer fb_tmp(width, height);
std::memcpy(&fb->frame_buffer, &fb_tmp, sizeof(FrameBuffer));
}
// ...
但我怀疑这不是解决这个问题的正确方法(我怀疑 fb_tmp
中的 Pixel
被分配到范围之外。
- 解决这个问题的正确方法是什么?
- 关于如何在 CPython 中公开复杂的 object 是否有一种众所周知的方法?
我已经成功使用了类似于
的代码
typedef struct {
PyObject_HEAD
FrameBuffer *frame_buffer;
} PyFrameBuffer;
然后
if (fb != nullptr)
{
fb->frame_buffer = new FrameBuffer( ... );
}
但是您必须考虑明确删除该对象。您需要在删除 C++ FrameBuffer
对象的 PyFrameBuffer
初始化中添加 tp_dealloc()
function:
delete fb->frame_buffer;
还有:
当您使用 C++ 创建 Python 扩展模块时,您正在链接代码的 C++ 运行时库。如果多个模块使用 C++,则它们 所有 都必须使用完全相同的 C++ 运行时库。
我有一个 Python object 引用 C++ object。
Header:
#define PY_SSIZE_T_CLEAN
#include <Python.h>
#include <structmember.h>
typedef struct {
PyObject_HEAD
FrameBuffer frame_buffer;
} PyFrameBuffer;
extern PyTypeObject PyFrameBuffer_type;
extern PyObject* PyFrameBuffer_NEW(size_t width, size_t height);
C++ FrameBuffer
class 如下:
class FrameBuffer {
public:
explicit FrameBuffer(const size_t width, const size_t height);
// ...
private:
size_t m_width;
size_t m_height;
std::vector<Pixel> m_pixels;
};
Pixel
是几个普通类型元素的简单 class。
PyFrameBuffer_NEW()
函数如下:
PyObject* PyFrameBuffer_NEW(size_t width, size_t height)
{
auto* fb = (PyFrameBuffer*) PyObject_NEW(PyFrameBuffer, &PyFrameBuffer_type);
if (fb != nullptr)
{
fb->frame_buffer = FrameBuffer(width, height);
}
return (PyObject*) fb;
}
此代码崩溃:
fb->frame_buffer
分配了未定义的值(fb->frame_buffer.m_pixels.size()
未定义)。
在 fb->frame_buffer
赋值期间,m_pixels
.
Pixel
的重新分配
所以,它崩溃了。
此代码似乎 有效:
/// ...
if (fb != nullptr)
{
FrameBuffer fb_tmp(width, height);
std::memcpy(&fb->frame_buffer, &fb_tmp, sizeof(FrameBuffer));
}
// ...
但我怀疑这不是解决这个问题的正确方法(我怀疑 fb_tmp
中的 Pixel
被分配到范围之外。
- 解决这个问题的正确方法是什么?
- 关于如何在 CPython 中公开复杂的 object 是否有一种众所周知的方法?
我已经成功使用了类似于
的代码typedef struct {
PyObject_HEAD
FrameBuffer *frame_buffer;
} PyFrameBuffer;
然后
if (fb != nullptr)
{
fb->frame_buffer = new FrameBuffer( ... );
}
但是您必须考虑明确删除该对象。您需要在删除 C++ FrameBuffer
对象的 PyFrameBuffer
初始化中添加 tp_dealloc()
function:
delete fb->frame_buffer;
还有:
当您使用 C++ 创建 Python 扩展模块时,您正在链接代码的 C++ 运行时库。如果多个模块使用 C++,则它们 所有 都必须使用完全相同的 C++ 运行时库。