"Value class instance" pattern?

Benjamin Thaut code at benjamin-thaut.de
Sat Jul 13 06:17:05 PDT 2013


I had the very same problem and I'm using a composite helper struct for 
this purpose:

struct DefaultCtor {}; //call default ctor type

struct composite(T)
{
   static assert(is(T == class),"can only composite classes");
   void[__traits(classInstanceSize, T)] _classMemory = void;
   bool m_destructed = false;
   debug {
     T _instance;
   }
   else
   {
     @property T _instance()
     {
       return cast(T)_classMemory.ptr;
     }

     @property const(T) _instance() const
     {
       return cast(const(T))_classMemory.ptr;
     }
   }

   alias _instance this;

   @disable this();
   @disable this(this); //prevent evil stuff from happening

   this(DefaultCtor c){
   };

   void construct(ARGS...)(ARGS args) //TODO fix: workaround because 
constructor can not be a template
   {
     _classMemory[] = typeid(T).init[];
     T result = (cast(T)_classMemory.ptr);
     static if(is(typeof(result.__ctor(args))))
     {
       result.__ctor(args);
     }
     else
     {
       static assert(args.length == 0 && !is(typeof(T.__ctor)),
                     "Don't know how to initialize an object of type "
                     ~ T.stringof ~ " with arguments:\n" ~ ARGS.stringof 
~ "\nAvailable ctors:\n" ~ ListAvailableCtors!T() );
     }
     debug _instance = result;
   }

   void destruct()
   {
     assert(!m_destructed);
     Destruct(_instance);
     debug _instance = null;
     m_destructed = true;
   }

   ~this()
   {
     if(!m_destructed)
     {
       Destruct(_instance);
       m_destructed = true;
     }
   }
}


I and I use it often (especially with containers, I always tend to 
forget newing containers, which can not happen with this helper struct 
because of @disable this();

Usage is something like the following:

class Foo
{
   int m_i;
   this()
   {
     m_i = 5;
   }

   this(int i)
   {
     m_i = i;
   }
}

class Bar
{
   composite!Foo m_foo;

   this()
   {
     m_foo = typeof(m_foo)();
     m_foo.construct(DefaultCtor()); // would call Foo.this()
     // alternative
     m_foo.construct(5); // would call Foo.this(int)
   }
}

I wrote this before constructors of structs could be templated, I plan 
on updating it so you can write

m_foo = typeof(m_foo)(5);

The m_destructed member is kind of optional, if the default destruction 
order is ok, you can omit it and save the additional bytes of overhead 
it imposes. A advantage is also that Foo is a normal class, you can 
inherit from it and you don't have to write any boilerplate code to use 
the value type of Foo.


More information about the Digitalmars-d mailing list