Logo Search packages:      
Sourcecode: virtualbox-ose version File versions

CIShared< D > Class Template Reference

#include <CIShared.h>

List of all members.


Detailed Description

template<class D>
class CIShared< D >

This template allows to implement the implicit sharing semantics for user-defined data structures.

The template argument is a structure (or a class) whose objects need to be implicitly shared by different pieces of code. A class generated from this template acts as a wrapper for that structure and provides a safe access (from the shared usage point of view) to its members. Note that simple C++ types (such as int) cannot be used as template arguments.

Implicit sharing means that instances of the generated class point to the same data object of the managed structure until any one of them tries to change it. When it happens that instane makes a deep copy of the object (through its copy constructor) and does the actual change on that copy, keeping the original data unchanged. This technique is also called "copy on write". Also, any instance can excplicitly stop sharing the data it references at any time by calling the detach() method directly, which makes a copy if the data is referenced by more than one instance.

The read-only access to the managed data can be obtained using the data() method that returns a pointer to the constant data of the type used as a template argument. The pointer to the non-constant data is returned by the mData() method, that automatically detaches the instance if necessary. This method should be used with care, and only when it is really necessary to change the data -- if you will use it for the read-only access the implicit sharing will not work because every instance will have its data detached.

To be able to be used with the VShared template the structure/class must have public (or protected) constructors and a destructor. If it doesn't contain pointers as its members then the two constructors (the default and the copy constructor) and the destructor automatically generated by the compiler are enough, there's no need to define them explicitly. If the destructor is defined explicitly it must be virtual.

The default constructor implemented by this template (it is actually a constructor with one bool argument that defaults to false) creates a null instance (i.e. its isNull() method returns false). All null instances share the same internal data object (created by the default constructor of the managed structure) and provide only a read-only access to its members. This means that the mData() method of such an instance will always return a null pointer and an attempt to access its members through that pointer will most likely cause a memory access violation exception. The template doesn't provide any other constructors (except the copy constructor) because it doesn't know how to initialize the object of the managed structure, so the only way to create a non-null instance is to pass true to the constructor mentioned above.

It's a good practice not to use instantiations of this template directly but derive them instead. This gives an opportunity to define necessary constructors with arguments that initialize the managed structure, as well as to define convenient methods to access structure members (instead of defining them in the structure itself). For example:

  // a data structure
  struct ACardData {
      string name;
      // commented out -- not so convenient:
      // void setName( const string &n ) { name = n; }
  }

  // a wrapper
  class ACard : publc CIShared< ACardData > {
      ACardData() {}  // the default constructor should be visible
      ACardData( const string &name ) :
          CIShared< ACardData >( false ) // make non-null
      {
          mData()->name = name;
      }
      string name() const { return data()->name; }
      void setName( const string &name ) { mData()->name = name; }
  }

  // ...
  ACard c( "John" );
  // ...
  c.setName( "Ivan" );
  // the above is shorter than c.data()->name or c.mData()->setName()

If some members of the structure need to be private (and therefore unaccessible through the pointers returned by data() and vData()) you can simply declare the wrapper class (the ACard class in the example above) as a friend of the structure and still use the above approach.

For public members of the original structure it's also possible to use the overloaded operator->(), which is the equivalent of calling the data() method, i.e.:

  // ...
  cout << c->name;

The operator!() is overloaded for convenience and is equivalent to the isNull() method.

The operator==() makes a comparison of two instances.

Todo:
put the "original" state definition here...

Definition at line 31 of file CIShared.h.


Public Member Functions

 CIShared (const CIShared &that)
 CIShared (bool null=true)
CIShared copy () const
const D * data () const
bool detach ()
bool detachOriginal ()
bool isNull () const
bool isOriginal () const
D * mData ()
bool operator! () const
const D * operator-> () const
CISharedoperator= (const CIShared &that)
bool operator== (const CIShared &that) const

Private Member Functions

 CIShared (Data *data)

Private Attributes

Datad

Static Private Attributes

static CIShared Null = CIShared( new Data( 0 ) )

Classes

class  Data

The documentation for this class was generated from the following file:

Generated by  Doxygen 1.6.0   Back to index