[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