tags:

views:

73

answers:

1

I am writing Qt-based app with Blender-like functionality.

It consists of a 'framework' which is GUI + plugin system and plugins. Plugins are Qt dlls with objects (e.g. a Sphere, a Box, etc.) that can be basically created and displayed. All those objects, once created, are stored in the framework in some kind of a container structure which holds shared_ptr's to them (so actually the container is pretty much like vector<shared_ptr<INode>>)

What I want is to use shared_from_this() function inside one of plugins. E.g. Here's a sample plugin (code changed for clarity):

class Q_DECL_IMPORT SphereNode: public INode, public Sphere

Where INode is:

class INode: public QObject, public boost::enable_shared_from_this<INode>

,a base class for everything stored in the container. So the problem is that this function:

void SphereNode::update()
{
 foo(shared_from_this());
}

throws a boost::bad_weak_ptr exception.

A couple of notes how this SphereNode is created (a Factory class)

boost::shared_ptr<INode> NodeFactory::createNode(const QString& type, QString tag)
{
...
QPluginLoader loader(filesPlugin_[i]);
boost::shared_ptr<QObject> plugin(loader.instance());
boost::shared_ptr<INode> iNodePlugin = boost::shared_dynamic_cast<INode>(plugin);
return iNodePlugin;
}

Any ideas?

+1  A: 

Perhaps it is this line:

boost::shared_ptr<INode> iNodePlugin = boost::shared_dynamic_cast<INode>(plugin);

Which should be replaced by:

boost::shared_ptr<INode> iNodePlugin = dynamic_cast<INode*>(loader.instance())->shared_from_this();

Maybe it has something to do with:

boost::shared_ptr<QObject> plugin(loader.instance());

Here plugin takes ownership of the returned instance. However, the Qt documentation states that the instance will be automatically freed by the QPluginLoader upon destruction.

However, this would rather cause a segfault (undefined behavior) than a regular boost::bad_weak_ptr exception.

If you want to prevent this, you can specify a null_deleter that will do nothing when the reference counter reachs 0.


Are you calling shared_from_this() from either a constructor or a destructor (directly or indirectly) ?

If so, there is your problem.

When you're in the constructor, the object is not fully created yet, so having a shared_ptr to it is invalid.

To avoid this issue, you can get your shared_ptr to the object in a factory method (that you already have anyway), when the object was succesfully constructed.

ereOn
Nope. First I create SphereNode with NodeFactory::createNode, then put it into the container, then call SphereNode::update(). So the constructor was called long ago before the actual call of shared_from_this()
Mikhail
@Mikhail: Added some elements to my answer. Not sure it helps though. Will continue to think about it.
ereOn
Thanks, I also think it's something with the ownership.Besides, is it okay that the first shared_ptr I create is shared_ptr<QObject>, where QObject is not inherited from boost::enable_shared_from_this? Can it be the reason why the weak_ptr inside enable_shared_from_this is null?
Mikhail
@Mikhail: I think this could definitely has something to do with. Check my (again updated ;) answer. I added a workaround that you might try.
ereOn
Thanks a lot ereOn, it really solved the problem:instead of boost::shared_ptr<QObject> plugin(loader.instance());I should have used boost::shared_ptr<INode> plugin(dynamic_cast<INode*>(loader.instance())) :)
Mikhail
You're welcome. I'm glad you got it working after all :)
ereOn