{tp_alloc,tp_dealloc}和{tp_new,tp_free}应该被视为对吗? [英] Should {tp_alloc, tp_dealloc} and {tp_new, tp_free} be considered as pairs?

查看:269
本文介绍了{tp_alloc,tp_dealloc}和{tp_new,tp_free}应该被视为对吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

是否确实应该在tp_dealloc中销毁在tp_alloc中创建的任何内容?同样适用于{tp_new,tp_free}吗?

Is it true that whatever is created in tp_alloc should be destroyed in tp_dealloc? And similarly for {tp_new, tp_free}?

它看起来很明显是对称的,但请您澄清一下.

It looks like an obvious symmetry, but I would be grateful for clarification.

我的实际用例是这样的: 我有:

My actual use case is this: I have:

class OSClass : PyObject {...}

class Final : OSClass {...}

因此对应的PyTypeObject pto具有:

pto->tp_basicsize = sizeof(FinalClass)
pto->tp_dealloc = (destructor) 
                  [](PyObject* pyob) { PyMem_Free(pyob); };

但是,新样式类将PyObject及其对应的C ++对象彼此分开存储,因此工作方式不同.

However the new style class stores the PyObject and its corresponding C++ object separately from one another, and therefore works differently.

它将在tp_new中创建PyObject,并在tp_init中创建相应的C ++对象.

It creates the PyObject in tp_new, and the corresponding C++ object in tp_init.

并在tp_dealloc中销毁它们两者

And destroys both of them in tp_dealloc

这是正确/最佳吗?

代码:

// extra void* to point to corresponding C++ object
pto->tp_basicsize = sizeof(PyObject) + sizeof(void*)

pto->tp_new = new_func;
pto->tp_init = init_func;
pto->tp_dealloc = dealloc_func;

static PyObject* new_func( PyTypeObject* subtype, PyObject* args, PyObject* kwds )
{
    // First we create the Python object.
    // The type-object's tp_basicsize is set to sizeof(Bridge)
    // (Note: We could maybe use PyType_GenericNew for this:
    //   http://stackoverflow.com/questions/573275/python-c-api-object-allocation )
    //
    PyObject* pyob = subtype->tp_alloc(subtype,0);

    Bridge* bridge = reinterpret_cast<Bridge*>(pyob);

    // We construct the C++ object later in init_func (below)
    bridge->m_pycxx_object = nullptr;

    return pyob;
}


static int init_func( PyObject* self, PyObject* args, PyObject* kwds )
{
    try
    {
        Object a = to_tuple(args);
        Object k = to_dict(kwds);

        Bridge* bridge{ reinterpret_cast<Bridge*>(self) };

        // NOTE: observe this is where we invoke the 
        //       constructor, but indirectly (i.e. through final)
        bridge->m_pycxx_object = new FinalClass{ bridge, a, k };
    }
    catch( Exception & )
    {
        return -1;
    }
    return 0;
}

static void dealloc_func( PyObject* pyob )
{
    auto final = static_cast<FinalClass*>( cxxbase_for(pyob) );

    delete final;
    PyMem_Free(pyob);

    COUT( "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" );
    //self->ob_type->tp_free(self);
}

推荐答案

来自 tp_new文档,您拥有

From the tp_new documentation you have

tp_new 函数应调用subtype->tp_alloc(subtype, nitems)为对象分配空间,然后仅在绝对必要的情况下进行更多的初始化.可以安全地忽略或重复的初始化应该放在 tp_init 处理程序中.一个好的经验法则是,对于不可变类型,所有初始化都应在 tp_new 中进行,而对于可变类型,大多数初始化应推迟至 tp_init .

The tp_new function should call subtype->tp_alloc(subtype, nitems) to allocate space for the object, and then do only as much further initialization as is absolutely necessary. Initialization that can safely be ignored or repeated should be placed in the tp_init handler. A good rule of thumb is that for immutable types, all initialization should take place in tp_new, while for mutable types, most initialization should be deferred to tp_init.

这就是为什么要在tp_new中创建对象本身并在tp_init中对其进行初始化的原因.创建C ++对象是初始化的一部分.由于 tp_init文档声明

That's why you create the object itself in tp_new and initialise it in tp_init. Creating the C++ object is part of the initialisation. Since the tp_init documentation states

此函数对应于类的 __ init __ ()方法.像 __ init __ ()一样,可以在不调用 __ init __ ()的情况下创建实例,并且可以通过调用实例的 __ init __ 重新初始化实例.再次>()方法.

This function corresponds to the __init__() method of classes. Like __init__(), it is possible to create an instance without calling __init__(), and it is possible to reinitialize an instance by calling its __init__() method again.

您需要检查bridge->m_pycxx_object != nullptr,并在出现故障时删除已初始化的实例或引发错误.

You need to check for bridge->m_pycxx_object != nullptr and delete the already initialised instance on failure or raise an error.

然后在tp_dealloc中销毁Python对象.由于C ++对象是该对象的一部分,因此也需要在该对象中销毁该对象.

In tp_dealloc you then destroy the Python object. Since the C++ object is part of this one, it needs to be destroyed there as well.

返回配对:您在tp_new中调用tp_alloc,在tp_dealloc中调用tp_free.因此{tp_alloctp_free}和{tp_newtp_dealloc}应该被视为对.

Back to the pairing: You call tp_alloc within tp_new and tp_free within tp_dealloc. So {tp_alloc, tp_free} and {tp_new, tp_dealloc} should be considered as pairs.

这篇关于{tp_alloc,tp_dealloc}和{tp_new,tp_free}应该被视为对吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆