Upon a bit of further reflection on this topic, I realized my suggestion
is doing something silly.
struct Element
{
Element(const Container * c, boost::python::object obj) :
_container(c), containerPyObj(obj) { }
std::string name() const;
const Container * _container;
boost::python::object containerPyObj;
};
Element GetElementProxy(boost::python::object self)
{
Container * container = boost::python::extract<Container *>(self);
return Element(container, self);
}
boost::python::object will handle the incref and decref for you if it's
a member of that class. No need to do it manually.
On 5/20/2014 9:48 AM, Jaedyn Draper wrote:
std::shared_ptr and similar types can also be used like so:
boost::python::class_<MyClass, std::shared_ptr<MyClass>>
But I don't think that would solve the problem because it's a raw
pointer to _container being held here. I don't think there's a way to
do what you want with raw pointers. The only way I would know of to do
that is to make
const Container * _container;
into
const std::shared_ptr<Container> _container;
or
const boost::shared_ptr<Container> _container;
or you can probably make this work with your own custom type, too, by
replacing the second argument to class_ with your C++ ref-counted
shared pointer class. Then anything exposed to python that deals with
the Container class (like the constructor for Element) should return
it or accept it as a shared_ptr instead of a pointer.
With raw pointers the ownership of the memory sits in just one place,
and you're deleting that place. This is an issue that goes deeper than
python, down to the C++ architecture - if you did the same thing in
C++ using raw pointers like that, you'd have the same behavior. In
order to get this sort of ref counting behavior in python, you have to
have it in C++.
In general, unless you're working with very performance-sensitive code
like a rendering pipeline (which isn't something you should use python
for, as it has relatively poor performance characteristics compared to
some other scripting languages - it's great for a lot of things, but
performance isn't one of them), I tend to advocate the use of
shared_ptr (or some similar memory management construct) over raw
pointers for long-term storage anyway. It can save you from a lot of
headaches and opens up a lot of possibilities when you combine it with
weak_ptr.
...
Of course, one other option that doesn't require shared pointers is to
set it up something like this:
struct Element
{
Element(const Container * c, PyObject * obj) : _container(c),
containerPyObj(obj)
{
Py_INCREF(containerPyObj);
}
~Element()
{
Py_DECREF(containerPyObj);
}
std::string name() const;
const Container * _container;
PyObject * containerPyObj;
};
Element GetElementProxy(boost::python::object self)
{
Container * container = boost::python::extract<Container *>(self);
return Element(container, self.ptr());
}
BOOST_PYTHON_MODULE(libkatya)
{
class_<Element>("Element", no_init)
.def("name", &Element::name)
;
class_<Container>("Container", init<std::string>())
.def("getElement", &GetElementProxy) // NOTE the change here,
it's calling the free function, not the member
;
}
Caveat, I haven't tested this code, so I don't know if it compiles,
but I've done similar things before. If you're dead set on not using
shared pointers for whatever reason, this should do what you want.
On 5/19/2014 1:27 AM, laan wrote:
Hi,
I'm having issues with Boost::Python objects that contain a reference
to a
c++ object:
--- C++ code ----
#include <boost/python.hpp>
struct Container;
struct Element
{
Element(const Container * c) : _container(c) { }
std::string name() const;
const Container * _container;
};
struct Container
{
Container(const std::string & s) : _string(s) { }
Element getElement()
{
return Element(this);
}
std::string name() const
{
return this->_string;
}
std::string _string;
};
std::string Element::name() const
{
return _container->name();
}
using namespace boost::python;
BOOST_PYTHON_MODULE(libkatya)
{
class_<Element>("Element", no_init)
.def("name", &Element::name)
;
class_<Container>("Container", init<std::string>())
.def("getElement", &Container::getElement)
;
}
--- Python Code ----------------------
container = test.Container("X")
elem = container.getElement()
del(container)
print(elem.name())
When calling elem.name(), it will reference the "container" object,
which
has been deleted, and I'm getting a segfault.
How can I make boost::python increment the reference counter of
Container
when an element containing a pointer to the Container is returned?
--
View this message in context:
http://boost.2283326.n4.nabble.com/Boost-Python-Reference-Counting-tp4662504.html
Sent from the Python - c++-sig mailing list archive at Nabble.com.
_______________________________________________
Cplusplus-sig mailing list
Cplusplus-sig@python.org
https://mail.python.org/mailman/listinfo/cplusplus-sig
_______________________________________________
Cplusplus-sig mailing list
Cplusplus-sig@python.org
https://mail.python.org/mailman/listinfo/cplusplus-sig
_______________________________________________
Cplusplus-sig mailing list
Cplusplus-sig@python.org
https://mail.python.org/mailman/listinfo/cplusplus-sig