Maintaining a std::set<boost::shared_ptr>
I'm writing a game and an accompanying engine in C++. The engine relies heavily on automation using a simple embedded scripting language. Scripts can create object classes, define event listeners on them, and produce instances from them. At present, an instance must be bound to a script-global identifier in order to preserve its existence. The obvious result of this is that there can be no anonymous objects, which wil开发者_运维知识库l be by far the most common.
At present, instances are managed using a std::set<Instance*, spatial_sort>
, where spatial_sort
is a functor that sorts instances by position, for rendering and collision detection. Instances are removed and re-inserted each frame using their current position as a hint, under the assumption that they're not likely to move a whole lot in a fiftieth of a second. If a dead
flag is set in the instance, it is erased from the set. The Instance
constructors and destructor invoke insert(this)
and erase(this)
, respectively.
In order to allow anonymous instances, I want to change the set to a std::set<boost::shared_ptr<Instance>, spatial_sort>
, which would allow Instance
to share ownership of instances and preserve their existence until they destroy themselves. Unfortunately, because the calls to insert()
need to be placed in the constructor, shared_from_this()
won't work for obtaining a shared_ptr
to the Instance
. It doesn't matter at all that Instance
happens to already inherit from boost::enable_shared_from_this<>
via its base class.
Can anyone recommend a suitable workaround?
Edit:
I did what I should have been doing in the first place, and split the behaviour of the Instance
class into two classes: Instance
and Reference
. The expression new SomeClass
in a script then returns a Reference
to a new Instance
. The Instance
objects themselves are never managed using a shared_ptr
, so they are responsible for committing suicide in response to a suitable event, e.g., end of animation, end of level, etc.
Thanks for the help! Refactoring is as good a solution as any if it Just Works.
You could add a static method to Instance
that you then use to create new objects and that also does the administrative stuff like adding it to the set:
static Instance* create(int something) {
boost::shared_ptr<Instance> sptr(new Instance(something));
instanceset.insert(sptr);
return sptr.get();
}
If you want to make this the only way to construct an object of this class you could also make the normal constructor private or protected.
For more on this see also the C++ FAQ Lite entry about "Dynamic binding during initialization", which is not directly related but uses the same technique to work around the restrictions on the use of virtual functions in constructors.
精彩评论