Why CleanupStack::PushL(CBase*) and not CleanupStack::PushL(CBase*&)?
| Mon, 2005-08-29 18:05 | |
|
Hi there, You've probably noticed that the CleanupStack PushL methods take a pointer by value instead of taking a pointer by reference. In my humble opinion it would make more sense if they were passed by reference. Ok, one of the results of that would be that you couldn't pass a temporary to PushL, but then when would you ever need to do that? Because PushL takes pointers by value the following (useless) example is broken: TInt method(HBufC*& aBuf) { aBuf = _L("Hello").Alloc() ; return 0 ; } HBufC* buf = NULL ; CleanupStack::PushL(buf) ; method(buf) ; // now buf points to "Hello" CleanupStack::PopAndDestroy(buf) ; // this causes a panic because buf now points to something else Anyone can find a good reason why the PushL methods don't take pointers by reference? Thanks, Nikolas. If we fall down it's so we can learn to pick ourselves up. |
|






Forum posts: 723
Nevertheless, I must admit that the special use case you mentioned below does not work. This way. Note that passing the expected item (i.e. the pointer) is a useful trick for debugging, but usually not used in a release (i.e. urel) build. And to be honest, I've never met such an expectation that I push sg onto the stack and expect the stack to pop sg else, just because the value of the pointer has changed in between. That's the reason why I said that it's a very special use case.
Cheers,
tOtE
Gabor Torok
Software architect, Agil Eight (http://www.agileight.com/)
Blog: http://mobile-thoughts.blogspot.com/
Forum posts: 12
www.italiasymbian.it for italian development
Forum posts: 1242
The cleanupstack exists so it can destroy objects you have created, either temporary with a lifespan only in one function, or ones you not yet can save the pointer too in a member variable, if a leave occours
Its not meant as a way to keep track of your pointers, its ment to ensure that objects get destroyed properly and it can't do that with a reference to a pointer...
It needs a pointer to the actual object.
If you don't have any possibly leaving L-functions between the allocation of the object, and the destruction, you don't need the cleanupstack at all!
Here is an (fully sane) example that wouldn't work with saving a ref. to a pointer:
iBitmap2 = new (ELeave) CFbsBitmap();
iBitmap2->Create(iBitmap1->SizeInPixels(),iBitmap1->DisplayMode());
CFbsBitmapDevice* fbsdev = CFbsBitmapDevice::NewL(iBitmap2);
CleanupStack::PushL(fbsdev);
CFbsBitGc* fbsgc = CFbsBitGc::NewL();
CleanupStack::PushL(fbsgc);
fbsgc->Activate(fbsdev);
fbsgc->BitBlt(TPoint(0,0),iBitmap1);
CleanupStack::PopAndDestroy(2); //pop from cleanupstack and destroy fbsgc, fbsdev
}
Say here that CFbsBitGc* fbsgc = CFbsBitGc::NewL(); leaves because of Out of memory.
Since the fbsdev pointer variable is on stack, it will no longer exist when the code in the TRAP harness, going through the cleanupstack runs.
So any reference saved to it would not longer be valid, and the CFbsBitmapDevice object would be lost, resulting in a memory leak.
(and most possibly a crash in the cleanupstack code, since it would be very hard to check for this case)