[C++-sig] Segfaults in object deallocation
Alex Leach
beamesleach at gmail.com
Sun Mar 24 20:22:02 CET 2013
Thanks for the reply, and apologies for the delay in mine; I've been
struggling with classes having protected destructors. Sorted now though..
On Sat, 23 Mar 2013 03:02:58 -0000, Niall Douglas
<s_sourceforge at nedprod.com> wrote:
>
> Separate C++ objects from their python wrappers. Have C++ objects
> held by shared_ptr.
>
> Have a custom deleter on shared_ptr invoke a virtual
> int_PythonIsAboutToDelete() function before it actually calls delete.
> You see as soon as destruction begins, all virtual functions cease to
> work, so you need a predestructor stage.
This seems to be on the right track. I had some success when calling a
Python-exposed __del__ method, with std::auto_ptr<Environment> as
argument. I had found - with lots of printf calls - that the C++
destructor was being called twice. Each time, it called
pthread_mutex_destroy, and being one too many times, that caused a
seg-fault. Seemed like an ownership problem, and calling 'release' on
std::auto_ptr<Environment>, in the exposed "__del__" method, got around
that seg-fault, running without error.
I was in the middle of replying with a success story, but on further
testing, it seemed that this solution only worked when the library was
linked against libpython3 / libboost_python3. When linking against the
version 2.7 counterparts, seg-faults crept back in... I couldn't
understand why...
With that partial success, I thought that I should define a corresponding
__new__ method, to allocate the memory for the object deleted by __del__.
Although that seems okay to me in principal, I'm completely failing to
write a successful implementation...
Are there any boost python helpers for this? Again, any help greatly
appreciated!
// wrapper class
namespace mylib {
class IEnvironment
: public notmylib::Environment
{
IEnvironment(const boost::python::list& envp);
~IEnvironment(void) {}
// method implementing __new__ functionality?
static boost::shared_ptr<IEnvironment> Create(
boost::python::object type,
const boost::python::list *envp );
}
// custom deleter
void DelEnvironment(boost::shared_ptr<IEnvironment> env);
// pointer to start of environment array
char** m_envp;
// thread and gil state vars
PyThreadState * _save;
PyGILState_STATE gil_state;
}
// First function to be called in initialisation chain.
const char* const* mylib::IEnvironment::InitEnvironment(const
boost::python::list& envp)
{
int envc = boost::python::len(envp);
pylib::m_envp = new char*[envc+1];
stl_input_iterator<char*> begin(envp) end;
int i=0;
while ( begin != end )
{
pylib::m_envp[i++] = (*begin);
begin++;
}
pylib::m_envp[i] = '\0';
pylib::gil_state = PyGILState_Ensure();
pylib::_save = PyEval_SaveThread();
return &pylib::m_envp[0];
}
// Defines initialiser chain. The function body here runs last.
mylib::IEnvironment::IEnvironment(const boost::python::list& envp)
: Environment(InitIEnvironment(boost::ref(envp)))
{
PyEval_RestoreThread(pylib::_save);
PyGILState_Release(pylib::gil_state);
}
// attempt at writing a __new__ method
boost::shared_ptr<mylib::Environment> mylib::Environment::Create(
boost::python::object cls, const boost::python::list& envp )
{
PyTypeObject* cls_type = (PyTypeObject*)cls.ptr();
PyObject* cls_inst = PyType_GenericNew( cls_type, envp.ptr(),
Py_None);
if (PyType_Ready(cls_type) != 0)
{
throw error_already_set();
}
// lots of trial and error here. Always in error, so far...
return boost::make_shared<pylib::IEnvironment>(
boost::python::extract<pylib::IEnvironment>(
boost::python::object(boost::python::ptr(cls_inst))));
}
BOOST_PYTHON_MODULE(foo)
{
boost::python::class_<mylib::Environment, boost::noncopyable,
boost::shared_ptr<mylib::IEnvironment>
("Environment", init<const boost::python::list&>() )
.def("__new__", &mylib::IEnvironment::Create )
.staticmethod("__new__") //< necessary?
.def("__del__", &pylib::DelEnvironment )
;
}
>>
> Do your pre destruction cleanup like destroying mutexs in that
> virtual function. Or indeed anything which can throw exceptions,
> because destructors are (soon to be) noexcept.
>
> Hope that helps,
> Niall
Yep, thanks!
Cheers,
Alex
--
Using Opera's mail client: http://www.opera.com/mail/
More information about the Cplusplus-sig
mailing list