[aspectc-user] AspectC++ and singletons?
Mike Mortensen
mmo at fc.hp.com
Wed Nov 21 00:35:48 CET 2007
Thank you Olaf for your insight on using 'within' to specify
calls of a method/function within some other function... Your
suggestion worked perfectly for me.
Now I have another question.... :-) I'm experimenting with
refactoring some design patterns using AspectC++.
One that I'm curious about is if the singleton pattern could be implemented
without the callers being aware. One benefit is that callers could
still use the
constructor call and the aspect could 'layer in' the singleton behavior...
For example, suppose I have the classic 'Shapes' hierarchy (Shape
superclass,
subclasses for Points, Circles, Lines, etc.) and also have some sort of
ShapeRegistry. In this somewhat contrived example, it would be nice if
applications could write code like this:
ShapeRegistry *sr1 = new ShapeRegistry();
sr1->addShape( key1, shape1);
sr1->addshape( key2, shape2);
and somewhere else in the code might be something like this:
ShapeRegistry *sr2 = new ShapeRegistry();
sr2->addShape( key3, shape3);
sr2->addshape( key4, shape4);
Again, I'm trying to quickly hack up an example singleton, but the basic
idea is
that I could use an aspect to intercept all constructor calls of
ShapeRegistry and
make sure that only one object is created and that all 4 objects (in my
example above)
are stored in the same registry, and that sr1 and sr2 both point to the
same object.
What I found (reading the docs and experimenting) is that it's easy to
'intercept'
the constructor calls:
pointcut CTOR() = construction("ShapeRegistry");
and I can use *either* tjp->that() or tjp->target() to get the address
of the
created object, and calling tjp->proceed() does indeed invoke the
constructor.
Here's my question though, suppose that I have a singleton (static
pointer to a ShapeRegistry*)
so that after the first call to the constructor I set that from NULL to
the first created ShapeRegistry
class. On any subsequent constructor call, is there any way to avoid
calling the constructor and
return a pointer to the other (already created) ShapeRegistry -- or
since the 'construction'
joinpoint is an execution of the constructor, is it 'too late' to avoid
the call -- in the sense that the
calling code is expecting the constructor to allocate new memory in the
location that 'tjp->that()
already points to?
Here's a snippet of code:
ShapeRegistry *srSingleton = NULL;
aspect ShapeSingleton {
pointcut CTOR() = construction("ShapeRegistry") &&
!within("ShapeSingleton");
advice CTR() : around() {
if( srSingleton ) {
cerr << " Already created a ShapeRegistry" << endl;
//*QUESTION* -- can I return srSingleton to the caller of 'new
ShapeRegistry();' ???
return;
}
tjp->proceed();
cerr << " that: " << tjp->that() << " target: " << tjp->target()
<< endl; //the that() and target() do match the pointer value I see in
the caller
srSingleton = tjp->that();
}
public:
ShapeSingleton() { cerr << "CreatingShapeSingleton ASPECT!" <<
endl;} //this isn't necessary since I'm using srSingleton,
// but gives just one aspect instead of one
aspect per joinpoint (constructor call)
};
It may be that singleton isn't the best use of aspects in AspectC++ --
I'm trying to see if others have used it
successfully with AspectC++.
I noticed that when Jan Hannemann implemented Singleton with AspectJ he
is able to take advantage of
several things:
1) around advice (in AspectJ) has a return type that matches
the pointcut
2) Java's memory allocation model for objects is simpler that
C++'s local versus heap allocation of objects
3) all object in Java are subtypes of Object
so that he can do this:
Object around(): call((Singleton+).new(..)) &&
!protectionExclusions() {
Class singleton =
thisJoinPoint.getSignature().getDeclaringType();
if (singletons.get(singleton) == null)
{ // How to access the static instance variable
here?
singletons.put(singleton, proceed());
}
return singletons.get(singleton);
}
Even supposing my singleton in AspectC++ works, I don't know that it
would work properly with
a 'heap'-based object:
ShapeRegistry *sr1 = new ShapeRegistry();
and a 'local' object:
ShapeRegistry sr3();
which may mean that this isn't a great idea to try and do in AspectC++...
Suggestions anyone?
Thanks!
-Mike
>Hi Mike,
>
>a lot of questions ...
>
>The within() pointcut functions matches all code join-points 'within' a
>specific lexical scope. Its argument has to be a name-pointcut, i.e.
>something static and *not*, for instance, execution(...). Therefore, you
>can simply use ...
>
>within("float CircleArea(float)") && call(...)
>
>... to match certains calls that are located within the CircleArea
>function. BTW, the syntax that you used (within("classname")) is the
>same as within ("% classname::%(...)") plus join-points located in the
>initialization of class members, e.g. static members. Also note that the
>argument of within() can be a (name-)pointcut expression of arbitrary
>complexity.
>
>
>
More information about the aspectc-user
mailing list