Contents
A Templated C++ Attribute Library for Object Persistence and Export
 
 
Printer-Friendly VersionPrinter-Friendly Version
 
Latest News
spacer View All spacer
 
November 22, 2009
 
Video Game Watchdog National Institute On Media And The Family Shutting Down [11]
 
Modern Warfare 2 Infinity Ward's 'Most Successful PC Version' Yet [12]
 
New Tech, Design Details Of Project Natal To Emerge At Gamefest In February
spacer
Latest Jobs
spacer View All     Post a Job     RSS spacer
 
November 22, 2009
 
Trion Redwood City
Sr. Evnironment Modeler
 
Trion Redwood City
Sr. Environment Artist
 
Sucker Punch Productions
3D Environment Artist
 
Sucker Punch Productions
Network Programmer
 
Sucker Punch Productions
Character Artist
 
Sucker Punch Productions
Texture Artist
 
Monolith Productions
Sr. Software Engineer, Engine - Monolith Productions - #113767
 
Sony Online Entertainment
Brand Manager
spacer
Latest Features
spacer View All spacer
 
November 22, 2009
 
arrow Upping The Craft: Susan O'Connor On Games Writing [6]
 
arrow Small Developers: Minimizing Risks in Large Productions - Part II [7]
 
arrow iPhone Piracy: The Inside Story [48]
 
arrow And Yet It Grows: Analyzing the Size and Growth of the European Game Market [5]
 
arrow NPD: Behind the Numbers, October 2009 [13]
 
arrow Reflecting On Uncharted 2: How They Did It [5]
 
arrow Sponsored Feature: Rasterization on Larrabee -- Adaptive Rasterization Helps Boost Efficiency
 
arrow Postmortem: Wadjet Eye's The Blackwell Convergence [2]
spacer
Latest Blogs
spacer View All     Post     RSS spacer
 
November 22, 2009
 
Time Fcuk
 
Accepting the Inherent Value of Games
 
Planckogenesis, Part II: Song Structure & Gravy Train [1]
spacer
About
spacer News Director:
Leigh Alexander
Features Director:
Christian Nutt
Editor At Large:
Chris Remo
Advertising:
John 'Malik' Watson
Recruitment/Education:
Gina Gross
 
Features
  A Templated C++ Attribute Library for Object Persistence and Export
by Gary McNickle
1 comments
Share RSS
 
 
June 4, 2008 Article Start Previous Page 2 of 5 Next
 

Attributes

Throughout this article, the definition of an "attribute" is a named reference to a variable. The AttributeContainer system provides a way to create attributes by "binding" them to a location in memory.

For example:

Advertisement

Container.Bind("player name", &m_name);

In this example, the member variable ‘m_name' is bound to the ID of ‘player name', which must remain unique within the ‘Container' object. Clients of Container then can query the value of this variable at any time by requesting that value from the container by ID.

name = Container.GetValue("player name");

The value of ‘m_name' can also be modified in the same manner, ie:

Container.SetValue("player name", "John Doe");

Yet attributes provide much more than glorified get/set mechanisms.

AttributeContainer is a template class which requires some knowledge of how to serialize the attributes it manages. This is done through the Policy pattern and is defined as:

template <class IO = AttributeContainerIO>
class AttributeContainer : public IO

The included library provides an example implementation of an XML I/O policy using TinyXML, but you can expand on these polices by implementing your own IO classes. Since all of the methods related to serialization are contained within the policy, and the AttributeContainer itself knows nothing of such things, you are not locked into any specific interface for serialization.

Defining an attribute container entails first implementing your IO policy and then passing that policy into the container definition like so:

AttributeContainer<AttributeContainerXmlIO>

I generally prefer to do this with a typedef:

typedef AttributeContainer<AttributeContainerXmlIO> t_XmlAttributeContainer;

Objects that wish to Bind member variables to this container, or to containers of this type, have a few choices. The safest way is for the object to inherit directly from the container, ie:

class myObj : public t_XmlAttributeContainer

By inheriting directly from AttributeContainer, you avoid situations where you might query a container for attributes of an object that has already been deleted. While this is the safest way, it does have one drawback, and that is memory usage. AttributeContainer is not a huge class (see memory considerations), but if you have thousands of instances of myObj, the overhead will add up quickly.

One alternative is to have a global instance of AttributeContainer (or at least one that is in a larger scope than the objects it manages). While this saves some memory, it does complicate use, as each bound attribute must be somehow uniquely identified per object.

Also, access into this global container must either be wrapped in checks to be sure the object in question still exists, or it must be removed from the container before the object is deleted. These hurdles can be easily solved by smart pointers who automatically manage removing the object from any associated containers or a number of other similar mechanisms.

However you choose to implement the container object, once all of your attributes are bound to the AttributeContainer, the container then can easily be used to serialize these attributes.

For example:

Listing 1

class myObj : public t_XmlAttributeContainer;
{
public:
myObj() {};

int m_Int;
float m_Float;
double m_Double;
};

myObj::myObj()
{
Bind("my_int", &m_Int);
Bind("my_float", &m_Float);
Bind("my_double", &m_Double, ATTR_READ_ONLY);
}

Assume that I want to serialize all ‘myObj' objects to disk. The t_XmlAttributeContainer object is a type of AttributeContainerXmlIO object, which implements the ReadXml and WriteXml methods, so the following code sample is an example of how this serialization might be done:

Listing 2

void myServer::Save()
{
TiXmlDocument doc;
TiXmlElement Xml("myObjects");

std::vector<myObj*>::iterator _i;
for (_i = m_objects.begin(); _i != m_objects.end(); _i++)
{
myObj* pObj = (*_i);

pObj->WriteXml(&Xml);
}
}

Every bound attribute of every myObj contained in the list of m_objects has been persisted to xml with the exception of the ‘my_double' attribute. This attribute was bound as ‘read only' and so was not written to the xml stream.

The member objects of the example myObj object are all built in types. What about complex types? AttributeContainer can bind and persist any type of object, as long as the << and >> stream operators exist for that type.

The example above bound member variables to a string id. But what about temporary variables, or variables created on the stack or on the heap? AttributeContainer provides safe ways to bind attributes regardless of their storage or scope but, as any object that deals with pointers does, it requires careful consideration.

 
Article Start Previous Page 2 of 5 Next
 
Comments

Andrew Ames
profile image
The biggest memory savings can be found by separating the attribute container into a class meta data object that is instantiated and filled only once for the class, instead of for each object instance.

After rereading the article, I see you mentioned this refactor potential:

"One alternative is to have a global instance of AttributeContainer (or at least one that is in a larger scope than the objects it manages). While this saves some memory, it does complicate use, as each bound attribute must be somehow uniquely identified per object."

There are certainly some not-too-difficult solutions that simplify the global shared container pattern for client code.

In a system I worked with, the following client code would serialize an object's properties to a stream:

Object *pObject = ...;

MutableString mutstr;
StringOutputStream sos(mutstr);
XmlSerializer ser(os);

ser.Serialize(pObject);


none
 
Comment:
 


Submit Comment