I have a class, Fixture, that I want to cast to a 3rd party library class, b2FixtureDef. Currently, my function looks like this:
Fixture::operator b2FixtureDef() const {
b2FixtureDef fd;
fd.density = m_density;
fd.friction = m_friction;
fd.isSensor = m_isSensor;
fd.restitution = m_restitution;
fd.shape = &b2PolygonShape(m_polygon); // <-- the problem
return fd;
}
Although this doesn’t produce any compile-time errors, I expect this will be a problem: fd.shape is a pointer. I’m casting my polygon object, to their polygon object, and then saving that location in memory. If I’m not mistaken, this will become immediately invalid after that line finishes executing.
So what’s a nice workaround for this? I could use the new operator, but my class shouldn’t really be allocating memory for some other class to clean up. I could actually store the b2PolygonShape in my class, but then I essentially have two copies of the same data (my polgon object, and their polygon object); I could get rid of mine, but it’s a lot easier to work with, which is why I created it in the first place. I could remove the entire function and make other classes responsible for doing the conversion themselves, but that wouldn’t be consistent with my other wrappers, and it isn’t a very nice solution. Is there any happy middle ground I’m overlooking?
Code now looks like this:
Fixture::operator b2FixtureDef() const {
b2FixtureDef fd;
fd.density = m_density;
fd.friction = m_friction;
fd.isSensor = m_isSensor;
fd.restitution = m_restitution;
fd.shape = new b2PolygonShape(m_polygon);
return fd;
}
And gets used like this:
void Body::addFixture(const Fixture& fixture) {
m_fixtures.append(fixture);
b2FixtureDef fd = fixture;
m_body->CreateFixture(&fd);
delete fd.shape;
}
My goal was that I could just go m_body->CreateFixture(&fixture) and it would cast fixture to a b2FixtureDef and free up the resources by itself… but it doesn’t look like that’s possible with this stupid pointer dangling around.
A conversion operator always has to make a copy of everything, so that the result is valid even if the original object is freed. Which means that you need to make a copy of
m_polygonas b2PolygonShape and assign a pointer to it to b2FixtureDef::shape.You can make a copy by implementing a copy constructor in b2PolygonShape or a conversion operator in whatever type
m_polygonis. […]b2FixtureDef::shape looks like a has-a relation, so the destructor of b2FixtureDef should free it anyway, doesn’t it?
Hmm, you say b2FixtureDef::shape is not freed automatically, what if you create a proxy class that has a b2FixtureDef as member and a conversion operator b2FixtureDef?
When you create the proxy object you create b2PolygonShape on the heap and fill the b2FixtureDef members just like in your code. In the conversion operator you simply return the b2FixtureDef member and in the proxy destructor you free the b2PolygonShape:
you then use it like this