[aspectc-user] AspectC++ and singletons?

Olaf Spinczyk Olaf.Spinczyk at informatik.uni-erlangen.de
Wed Nov 21 11:04:31 CET 2007


Hi Mike,

at the moment AspectC++ does not support the interception of constructor 
calls on the client side. The 'construction' advice is something like 
'execution' advice for the constructor. When the constructor is 
executed, the memory for the object has already been allocated. 
Therefore, this language feature doesn't help you.

Besides a language extension the only solution that I see at the moment 
is to introduce another level of indirection. For example, you could use 
a smart pointer type as a proxy.

My impression is that you first should try to find out what the pattern 
is and how it would be implemented without aspects. As soon as this is 
done, we can try to find out if the implementation of the pattern can be 
simplified with AspectC++. The classic Singleton pattern can be 
implemented with AspectC++ very well, but your goal is much more ambitious.

- Olaf

Mike Mortensen wrote:
> 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