使用boost :: python :: handle作为临时?

时间:2015-09-17 13:48:19

标签: boost-python

在自定义转换器中,我正在检查序列项是否是某种类型。到目前为止,我已经有了这个代码(简化)

How many copies of data are backed-up? 

但这是因为PySequence_GetItem is returning a new reference而泄露了内存。所以要么我可以在循环中做这样的事情:

namespace bp=boost::python;
/* ... */
static void* convertible(PyObject* seq_ptr){
    if(!PySequence_Check(seq_ptr)) return 0;
    for(int i=0; i<PySequence_Size(seq_ptr); i++) 
        if(!bp::extract<double>(PySequence_GetItem(seq_ptr,i)).check()) return 0;
    /* ... */
}
/* ... */

但这很笨拙;我可以做一个独立的功能,但这是我回忆起PyObject* it=PySequence_GetItem(seq_ptr,i); bool ok(bp::extract<double>(it).check(); Py_DECREF(it); // will delete the object which had been newly created if(!ok) return 0; 实施引用计数机制的地方;所以这样的事情可能会这样:

bp::handle

但是this page提到使用句柄作为临时工作是不鼓励的。为什么?在实际调用if(!bp::extract<double>(bp::handle<>(PySequence_GetItem(seq_ptr,i))).check()) return 0; 之前,是否可以销毁对象?有没有其他优雅的方式来写这个?

1 个答案:

答案 0 :(得分:1)

在调用.check()之前,对象不会被销毁,并且在发布的上下文中是安全的。

不使用临时工具的建议是由于参数评估和异常安全的未指定顺序。如果只有一个订单可以评估参数,例如在您的示例中,那么它是安全的。例如,考虑函数bad(),它总是抛出异常:

f(boost::python::handle<>(PySequence_GetItem(...)), bad());

如果在bad()PySequence_GetItem(...)之间评估boost::python::handle<>(...),那么新的引用将会泄漏,因为堆栈将在构建boost::python::handle<>之前开始展开。另一方面,当使用非临时性时,在PySequence_GetItem()boost::python::handle<>()之间不可能抛出某些东西,因此在出现异常情况下,以下内容是安全的:

boost::python::handle<> item_handle(PySequence_GetItem(...));
f(item_handle, bad());

考虑阅读Herb Sutter的GotW #56: Exception-Safe Function Calls了解更多细节。