[C++-sig] Shared_ptr created by python wrapper doesn't know about the python reference?
Thomas Schipolowski
schipo at dynamik.fb10.TU-Berlin.DE
Mon May 2 14:20:40 CEST 2005
Hello,
in my c++ extension I have two classes which refer to each other,
creating a reference cycle. Since 'Slave' objects are useless without an
associated 'Master', I want to store the backward reference from the
Slave to its Master using boost::weak_ptr. To further complicate things,
I have different variants of the Master class implemented by
inheritance. Only references to the base class are passed around with
boost::shared_ptr. Please have a look at the test case below. The
scenario works as expected when the objects are created in c++:
>>> import test as t
>>> m = t.create_master()
Slave::Slave(master_ptr)
master_ptr use count 2
master_ptr addr 12411040
weak_ptr use count 2
>>> m.status()
MDerived::status() ==> Master::status()
master addr 12411040
slave use count 1
Slave::status()
master use count 1
>>> s = m.slave
>>> del m
>>> s.status()
Slave::status()
master use count 0
>>>
The Master reference held by the Slave is valid as long as the Python
Master object is alive. Fine. However, this is not the case when the
MDerived and Slave objects are constructed from Python:
>>> m = t.MDerived()
>>> m.slave = t.Slave(m)
Slave::Slave(master_ptr)
master_ptr use count 3
master_ptr addr 12410784
weak_ptr use count 3
>>> m.status()
MDerived::status() ==> Master::status()
master addr 12410784
slave use count 1
Slave::status()
master use count 0
>>>
The Master reference held by the weak_ptr expires as soon as the Slave
constructor finishes, although m is still alive. I wonder what the
temporary shared_ptr did to the master object when the ref count went to
zero in this moment? Note however that the behavior is as expected if
the base class m = t.Master() is used instead of m = t.MDerived().
Please advise me on how to handle this situation correctly. It should
work the same no matter whether objects are created from python or c++.
Regards,
Thomas.
The test code (sorry, its rather long):
#include <iostream>
#include <boost/shared_ptr.hpp>
#include <boost/weak_ptr.hpp>
#include <boost/python.hpp>
using namespace boost;
using namespace boost::python;
class Master;
typedef shared_ptr<Master> pMaster;
typedef weak_ptr<Master> wpMaster;
class Slave {
public:
Slave(pMaster m): master(m) {
std::cout << "Slave::Slave(master_ptr)" << std::endl;
std::cout << " master_ptr use count " << m.use_count() <<
std::endl;
std::cout << " master_ptr addr " << (long)m.get() << std::endl;
std::cout << " weak_ptr use count " << master.use_count() <<
std::endl;
};
void status() {
std::cout << "Slave::status()" << std::endl;
std::cout << " master use count " << master.use_count() <<
std::endl;
};
wpMaster master;
};
typedef shared_ptr<Slave> pSlave;
class Master {
public:
virtual ~Master() {};
virtual void status() {
std::cout << "Master::status()" << std::endl;
std::cout << " master addr " << (long)this << std::endl;
std::cout << " slave use count " << slave.use_count() << std::endl;
if (slave) slave->status();
};
pSlave slave;
};
class MDerived: public Master {
public:
//no modifications, the point is to demonstrate
//that inheritance changes the behavior
virtual ~MDerived() {};
virtual void status() {
std::cout << "MDerived::status() ==> ";
Master::status();
};
};
typedef shared_ptr<MDerived> pMDerived;
pMaster create_master() {
pMaster m(new MDerived());
pSlave s(new Slave(m));
m->slave = s;
return m;
}
BOOST_PYTHON_MODULE(test)
{
class_<Slave, pSlave>("Slave", init<pMaster>())
.def("status", &Slave::status)
;
class_<Master, pMaster>("Master", init<>())
.def_readwrite("slave", &Master::slave)
.def("status", &Master::status)
;
class_<MDerived, pMDerived, bases<Master> >("MDerived", init<>())
;
def("create_master", create_master);
}
I am using VC6 with boost-build v1 and boost_1_32_0 on Windows. The
Python version is 2.3.4
More information about the Cplusplus-sig
mailing list