| Reply | « Previous Thread | Next Thread » |
|
If i got the point, there´s another solution to handle this:
http://www.parashift.com/c++-faq-lit....html#faq-17.4 Wiki Contributor of the Month (May). Winner of the May Contest on Wiki. |
| cabezonxdg |
| View Public Profile |
| Find all posts by cabezonxdg |
|
Quote:
|
| simo.salminen |
| View Public Profile |
| Find all posts by simo.salminen |
|
My summary:
Lets recap. Original issue was that why this code does not work: Code:
"""
CWidget::CWidget()
{
CleanupStack::PushL(this);
iDoodad=new(ELeave) CDoodad;
iWotsit=new(ELeave) CWotsit;
CleanupStack::Pop();
}
//usage:
CWidget* x=new(ELeave) CWidget;
CleanupStack::PushL(x);
x->FooL();
CleanupStack::PopAndDestroy(x);
"""
Quote:
Why? When User::Leave occurs in derived class constructor, it will cause cleanup stack to be destroyed on that level. This will cause destructors to be called for the class and its bases. After cleanup stack is cleaned, the User::Leave will throw exception (XLeaveException). Because of the C++ rules, this will cause call to already constructed base class destructors. When base class destructor is attempted to run again, it will cause crash, because the object has already been destroyed. The original explanation is bit unclear. It makes sense if one assumes that the original designers saw at the time, that if someday c++ exceptions are enabled, this would be a problem. So it seems that even though Symbian didn't have c++ exception handling at the time, the designers were smart enough to future-proof the design. IMO Symbian has one of the best exception/error handling mechanisms, and this is further proof that it is really well thought out. Lets further speculate what would happen if this design pattern would have been chosen at the time: - As mentioned, it would not have been future-proof. One would not have been able to enable c++ exceptions in Symbian because it would have caused major code re-write. - Using BaseConstructL/ConstructL pattern is slighly more efficient than PushL/Pop in base and child class. - It would have violated the L suffix naming convention (unless one would have renamed the classes with L which would have been somewhat ugly). - If ctors could leave, there is issue with "C* c = new C();". This kind of code would have required TRAP (new does not leave, but the ctor can, so error checking is bit complicated). - According to C++ rules, object lifetime starts when its constructor is executed succesfully. Calling object destructor before its lifetime has started could lead to some weird problems in some special cases. Note that this destructor calling before lifetime is started is what happens if object is pushed to cleanup stack in constructor and leave occurs. However, there is at least couple upsides if this pattern would have been chosen: - Simpler (no two-phase construction). - I've seen code where allocation is done in ctor (in a way that it does not leave). If OOM occurs, a flag is set. Then this flag is checked in all member functions, and they leave if the initial memory allocation in ctor has failed. Its kind of "deferred leaving". I think this was an existing base class, so adding (Base)ConstructL is not possible without API break. Interesting speculation is that if ctor would be allowed to leave, this change could have been done without this "deferred leaving". Thanks to all for your comments and bringing clarity to the issue!
Last edited by simo.salminen : 2008-05-15 at 10:50.
Reason: clarified the reason why it crashes, also added one more reason why it should not be used
|
| simo.salminen |
| View Public Profile |
| Find all posts by simo.salminen |
|
Hi,
I'm rather late to the party on this thread - only just saw it via the latest code clinic on SDN. I've actually been asking this very question for years in various training courses. One additional answer I got that did actually make sense (and is part of the reason why we have leaves and the cleanup stack at all) is that Symbian (EPOC32 as it was then) was first developed when C++ was very new and the compilers were far from standard in their behaviour. The pattern discussed here to avoid 2-phase construction worked on some compilers and not others (which is probably the origin of the vague explanation in the old SDK). Sorcery |
| Sorcery-ltd |
| View Public Profile |
| Find all posts by Sorcery-ltd |
|
Mark,
Good to bring this thread back, I had also missed it.. Personally, I'd rely on smart pointers and throw exceptions in the constructor.. this is closer to standard C++ and I think we're at the right time to start using these idioms, at least for engine code (and of course, provided you work solely on 3rd edition). On some other code (like UI) that relies heavily on Symbian idioms could still need to rely on this.. Also, having OpenC++ available now, Boost provides excelent smart pointers implementations (scoped, ref counted, etc..) |
| david.caabeiro |
| View Public Profile |
| Find all posts by david.caabeiro |
|
Quote:
If you implement CWidget such that the constructor leaves, and then call CWidget* widget = new CWidget(); You find the memory for widget is freed by C++ exception processing (and if you use smart pointers within CWidget, then anything the constructor allocates is freed). But if you use CWidget* widget = new (ELeave) CWidget(); then bang! If CWidget() leaves, you get an ALLOC panic, for the memory allocated to store widget. So it's a bit risky to rely on standard behaviour when, at present, Symbian OS doesn't guarantee it. |
|
PS: The code clinic Sorcery referred to is here: http://developer.symbian.com/main/su...2008/index.jsp
I don't cover the point I mentioned above because it complicated the issue and strayed too far from the original thread. But I think it's worth mentioning... |
| Reply | « Previous Thread | Next Thread » |
| Thread Tools | Search this Thread |
|---|---|
| Thread | Thread Starter | Forum | Replies | Last Post |
|---|---|---|---|---|
| Form not displayed when is created in Container ConstructL | redbart | Symbian User Interface | 2 | 2008-04-01 11:30 |
| Tool to find the needed capabilities | gaurav C | Symbian Tools & SDKs | 4 | 2008-03-25 13:30 |
| beginner's question:difference between ConstructL and BaseConstructL | 021850524 | General Symbian C++ | 3 | 2007-07-19 10:54 |
| How to set number for forwarding?? | silviuccia | General Symbian C++ | 6 | 2007-01-09 11:16 |
| help needed | rajiv_614 | General Browsing | 2 | 2006-04-17 12:56 |