Question

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 will 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.

Was it helpful?

Solution

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top