在自定义转换器中,我正在检查序列项是否为某种类型。到目前为止,我已经完成了这段代码(简化)
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;
/* ... */
}
/* ... */但这是内存泄漏,因为GetItem正在返回一个新的引用。所以要么我可以在循环中做这样的事情:
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实现引用计数机制的地方;所以,类似这样的事情可能会做到:
if(!bp::extract<double>(bp::handle<>(PySequence_GetItem(seq_ptr,i))).check()) return 0;但是此页提到使用句柄作为临时人员是不可取的。为什么?在实际调用.check()之前,可以销毁该对象吗?还有其他优雅的方式来写这个吗?
发布于 2015-09-17 15:59:24
在调用.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的GotW #56:异常安全函数调用。
https://stackoverflow.com/questions/32631982
复制相似问题