"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