在自定义转换器中,我正在检查序列项是否是某种类型。到目前为止,我已经有了这个代码(简化)
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;
之前,是否可以销毁对象?有没有其他优雅的方式来写这个?
答案 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了解更多细节。