Object Management

Started by
1 comment, last by marcusz 17 years, 11 months ago
I need to have a way to manage objects efficiently for my engine based on several goals and the solution I came up with doesn't seem to be efficient. Can someone provide suggestions? Sorry about the length, but it is a system design. You may skim to get the basic idea. Thanks. Objective of object management includes: • Object creation and destruction across dynamic libraries – In Windows, problems arise when an object dynamically created is not destroyed within the same address space. In order to resolve the situation, all compilation must be linked to the Multithreaded DLL version of the C Run-Time (CRT) libraries. In addition, this also allows STL to be used across DLLs. • Shared objects – It is often efficient to share and instance of an object rather creating multiple instances. The problems that are inherent with object sharing must be addressed. • Ease of object destruction – When there are many references to an instance of an object, it might be undesirable to manually release each reference in order to destroy the object. Thus, it is desirable to have the ability to destroy the object from one locality and not sacrifice the system’s stability. Ownership All objects have a single “owner” that creates and destroy the object. The owner therefore tracks the creation address space and destroys the object properly. To address the issue of shared object, assign each instance of a particular type to have a unique identification. An object could be referenced through this ID. A reference in this case is a specialized “smart pointer”. When a reference is requested, it is done through the owner, which registers the reference. The reference in this sense is not a handle to the object in that it can be used like a pointer. When an object is destroyed, the owner must notify all existing references. This way, an object can be explicitly destroyed in one place rather than “releasing” each reference manually. When a reference is release manually however, it should be unregistered. If objects are not explicitly destroyed, they will be destroyed when owner is destroyed. In this sense, memory is managed because all objects are ultimately “owned”. Implementation Considerations: • Note that each manager or owner must keep track each individual instance of a particular object type and for each instance each individual reference must also be managed. Since each object instance is identified by a unique ID and is exposed externally, a map using the ID as the key might be well suited. References on the other hand are kept track only for internal management and are not identified by an ID. However, they must be unique for each object instance of a particular type. This can be established using their memory address as the mapping key. This leads to three maps, one mapping object ID to instance, another mapping object ID to a map of references, and the final map maps reference address to reference. The use of map is to improve search (to remove a particular reference for example) performance. However, in this case searching is the degradation factor of performance. For reference management, this could be avoided with a little interdependency introduced. A non-associative container, say a list, may be used in place of a map. The necessary requirement is that iterators are never invalidated. Hence, each reference maintains the unique iterator and when necessary passes it to the manager. The manager then can directly refer to the reference in constant time. Again, this requires references to know and be dependent on how the manager implements their management. Pointer - The implementation is based on the "ownership" methodology in that each object of a particular type is "owned" or "managed" by another object that is responsible for creating and destroying the object. Each instance of the Pointer template contains a static templated member pointer that points to the "manager" object for the object type and a templated member pointer to the object. Since the manager keeps track of registered references so that each reference may be notified upon an event ( i.e the object has been destroyed ), the pointer to the manager is used to automate the registration process and being static assumes each particular type of object only has one manager. Since each reference is registered with the manager on construction and is unregistered on destruction, the extra overhead deserves some attention. Using Pointer in a temporary manner ( i.e. function parameter, returned object ) leads to unnecessary registrations. This effect also persist with assignment of references. A type casting operator is implemented so that Pointer can be type casted to a pointer of the particular object type in order to alleviate situations similar to the above mentioned.
Advertisement
Is this post too long to get a reply?
Hum-hum...

I use this:

std::map<TGameObjectID, boost::shared_ptr<CGameObject> > gMyObjectManager;


Then I use boost::shared_ptr<CGameObject> or boost::weak_ptr<CGameObject> everywhere to refer to the GO:s, depending on if I need to share the ownership or just track the lifetime of a GO.

To lookup a GO from an ID, I use gMyObjectManager.find(someID);

I'm not sure if this works across DLL:boundraries, though.


/Marcus

This topic is closed to new replies.

Advertisement