00001 // Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies). 00002 // All rights reserved. 00003 // This component and the accompanying materials are made available 00004 // under the terms of "Eclipse Public License v1.0" 00005 // which accompanies this distribution, and is available 00006 // at the URL "http://www.eclipse.org/legal/epl-v10.html". 00007 // 00008 // Initial Contributors: 00009 // Nokia Corporation - initial contribution. 00010 // 00011 // Contributors: 00012 // 00013 // Description: 00014 // 00015 00016 #include <f32file.h> 00017 #include <e32cons.h> 00018 #include <euserhl.h> 00019 00020 00021 _LIT(KTxtExample,"EUsableExample\n"); 00022 _LIT(KTxtPressAnyKeyToContinue,"Press any key to continue\n"); 00023 00024 CConsoleBase* gConsole; 00025 00032 _LIT(KPath, "c:\\a\\b\\c"); 00033 _LIT(KOne, "One "); 00034 _LIT(KTwo, "Two "); 00035 _LIT(KTesting, "Testing "); 00036 00037 void MaybeLeave() 00038 { 00039 // Some code that may leave 00040 } 00041 00042 HBufC* AllocateNameL(const TDesC& aDes) 00043 { 00044 return aDes.AllocL(); 00045 } 00046 00047 void GetCurrentPath(TDes& aDes) 00048 { 00049 aDes = KPath; 00050 } 00051 00052 void GetCurrentPathString(LString& aString) 00053 { 00054 aString = KPath; // Will auto-grow if necessary, may leave 00055 } 00056 00057 LString AppendCurrentPathStringL(LString aString) 00058 { 00059 /* 00060 This method accepts and returns LStrings by value. It works but 00061 is not recommended due to the inherent inefficiencies. 00062 */ 00063 LString result(aString); 00064 result += KPath; 00065 return result; 00066 } 00067 00068 class CTicker : public CBase 00069 { 00070 public: 00071 void Tick() { ++iTicks; } 00072 void Tock() { ++iTocks; } 00073 00074 void Zap() { delete this; } 00075 00076 public: 00077 TInt iTicks; 00078 TInt iTocks; 00079 }; 00080 00081 // Defines a custom pointer cleanup policy that calls the Zap member 00082 class TTickerZapStrategy 00083 { 00084 public: 00085 static void Cleanup(CTicker* aPtr) 00086 { 00087 /* 00088 The general template/class scaffolding remains the same 00089 for all custom cleanups, just this cleanup body varies 00090 */ 00091 aPtr->Zap(); 00092 _LIT(KTxtPrintZapp, "Zapped CTicker\n"); 00093 gConsole->Printf(KTxtPrintZapp); 00094 } 00095 }; 00096 00097 void RegisterTicker(CTicker& aTicker) 00098 { 00099 (void)aTicker; 00100 } 00101 00102 void RegisterTickerPtr(CTicker* aTicker) 00103 { 00104 (void)aTicker; 00105 } 00106 00107 void TakeTickerOwnership(CTicker* aTicker) 00108 { 00109 delete aTicker; 00110 } 00111 00112 void RegisterTimer(RTimer& aTimer) 00113 { 00114 (void)aTimer; 00115 } 00116 00117 // Defines a custom handle cleanup policy that calls Cancel() then Close() 00118 class TCancelClose 00119 { 00120 public: 00121 template <class T> 00122 static void Cleanup(T* aHandle) 00123 { 00124 /* 00125 The general template/class scaffolding remains the same 00126 for all custom cleanups, just this cleanup body varies 00127 */ 00128 aHandle->Cancel(); 00129 aHandle->Close(); 00130 _LIT(KTxtCancel,"Cancel Closed RTimer\n"); 00131 gConsole->Printf(KTxtCancel); 00132 } 00133 }; 00134 00135 void BespokeCleanupFunction(TAny* /*aData*/) 00136 { 00137 _LIT(KTxtCleanup,"BespokeCleanupFunction\n"); 00138 gConsole->Printf(KTxtCleanup); 00139 } 00140 00141 // The walkthroughs themselves 00142 00149 class CStringUserTwoPhase : public CBase 00150 { 00151 public: 00152 static CStringUserTwoPhase* NewL(const TDesC& aName) 00153 { 00154 /* 00155 We can use the resource management utility classes in 00156 two-phase if we want. 00157 */ 00158 LCleanedupPtr<CStringUserTwoPhase> self(new(ELeave) CStringUserTwoPhase); 00159 self->Construct(aName); 00160 /* 00161 Calling Unmanage() disables cleanup and yields the 00162 previously managed pointer so that it can be safely 00163 returned 00164 */ 00165 return self.Unmanage(); 00166 } 00167 00168 virtual void Construct(const TDesC& aName) 00169 { 00170 /* 00171 This assignment may leave if LString fails to allocate a 00172 heap buffer large enough to hold the data in aName 00173 */ 00174 iName = aName; 00175 } 00176 00177 ~CStringUserTwoPhase() 00178 { 00179 // The iName LString cleans up after itself automatically 00180 } 00181 00182 const TDesC& Name() 00183 { 00184 // We can just return an LString directly as a const TDesC 00185 return iName; 00186 } 00187 00188 protected: 00189 CStringUserTwoPhase() 00190 { 00191 /* 00192 Everything interesting happens in ConstructL in this 00193 version. 00194 00195 Default initialization of the iName LString does not 00196 allocate a heap buffer, and so cannot leave. As long as 00197 initialization is deferred to ConstructL, LStrings can be 00198 used safely with two-phase construction. 00199 */ 00200 } 00201 00202 protected: 00203 LString iName; 00204 }; 00205 00217 class CStringUserSinglePhase : public CBase 00218 { 00219 public: 00220 /* 00221 This macro is necessary to ensure cleanup is correctly handled 00222 in the event that a constructor may leave beneath a call to 00223 new(ELeave) 00224 */ 00225 CONSTRUCTORS_MAY_LEAVE 00226 00227 static CStringUserSinglePhase* NewL(const TDesC& aName) 00228 { 00229 return new(ELeave) CStringUserSinglePhase(aName); 00230 } 00231 00232 ~CStringUserSinglePhase() 00233 { 00234 // The iName LString cleans up after itself automatically 00235 } 00236 00237 const TDesC& Name() 00238 { 00239 // We can just return an LString directly as a const TDesC 00240 return iName; 00241 } 00242 00243 protected: 00244 CStringUserSinglePhase(const TDesC& aName) 00245 /* 00246 This initialization of iName may leave because LString 00247 needs to allocate a heap buffer to copy the aName string 00248 data into 00249 */ 00250 : iName(aName) 00251 { 00252 /* 00253 If iName initialization is successful but the constructor 00254 then goes on to leave later, iName (like all fields fully 00255 constructed at the point of a leave in a constructor) will 00256 be destructed, and so clean up after itself 00257 */ 00258 MaybeLeave(); 00259 } 00260 00261 protected: 00262 LString iName; 00263 }; 00264 00265 00266 void WalkthroughStringsL() 00267 { 00268 _LIT(KTxtOption1,"Option1: String handling using EUser high level library\n"); 00269 gConsole->Printf(KTxtOption1); 00270 _LIT(KTxtFormatString,"String %d"); 00271 _LIT(KTxtPrintString,"String %d = %S\n"); 00272 { 00273 // Trivially exercise the LString using classes defined above 00274 00275 LCleanedupPtr<CStringUserTwoPhase> one(CStringUserTwoPhase::NewL(KOne)); 00276 _LIT(KTxtSinglePhaseConstructor,"Single phase name: %S\n"); 00277 gConsole->Printf(KTxtSinglePhaseConstructor, &one->Name()); 00278 00279 LCleanedupPtr<CStringUserSinglePhase> two(CStringUserSinglePhase::NewL(KTwo)); 00280 _LIT(KTxtTwoPhaseConstructor,"Single phase name: %S\n"); 00281 gConsole->Printf(KTxtTwoPhaseConstructor, &two->Name()); 00282 00283 gConsole->Printf(KTxtPressAnyKeyToContinue); 00284 gConsole->Getch(); 00285 // Both instances are automatically deleted as we go out of scope 00286 } 00287 00288 { 00289 /* 00290 A default constructed LString starts empty, doesn't 00291 allocate any memory on the heap, and therefore the 00292 following cannot leave 00293 */ 00294 LString s; 00295 00296 /* 00297 But it will grow on demand if you assign to it, so it has 00298 enough space to hold the copied string data, and so 00299 assignment may leave 00300 */ 00301 s = KOne; 00302 00303 /* 00304 Similarly if you append to it with the leaving variant of 00305 Append(), AppendL(), if may grow on demand 00306 */ 00307 s.AppendL(KTwo); 00308 00309 // The += operator for LString also maps to AppendL() 00310 _LIT(KThree, "Three "); 00311 s += KThree; 00312 00313 /* 00314 You can also use new leaving format methods that also grow 00315 on demand 00316 */ 00317 s.AppendFormatL(KTesting); 00318 00319 /* 00320 This general style of use of LString may be preferable to 00321 typical descriptor use for a number of reasons e.g. it 00322 avoids the common temptation to set an artificial maximum 00323 buffer size; it avoids massive conservative over-allocation 00324 when the average case length of a string is far less than 00325 the worst-case maximum; it will not surprise you (compared 00326 to the alternative of a large stack-allocated TBuf) by 00327 triggering stack overflow. 00328 */ 00329 00330 // An LString can be printed the same way as any descriptor 00331 _LIT(KTxtValue,"Value: %S\n"); 00332 gConsole->Printf(KTxtValue, &s); 00333 00334 // An LString can be compared the same way as any descriptor 00335 _LIT(KTxtLStringCompare," Comparing LString with a literal is successful\n"); 00336 _LIT(KPhrase, "One Two Three Testing "); 00337 if(s == KPhrase) 00338 { 00339 gConsole->Printf(KTxtLStringCompare); 00340 } 00341 00342 // An LString supports all TDesC and TDes methods 00343 _LIT(KTxtLStringSupportedAPI1,"LString supports TDesC and TDes methods\n"); 00344 if(s.Find(KTwo) == 4) 00345 { 00346 gConsole->Printf(KTxtLStringSupportedAPI1); 00347 } 00348 // An LString supports all TDesC and TDes operators 00349 _LIT(KTxtLStringSupportedAPI2,"LString supports TDesC and TDes operators\n"); 00350 if(s[4] == TChar('T')) 00351 { 00352 gConsole->Printf(KTxtLStringSupportedAPI2); 00353 } 00354 TInt untrimmed = s.Length(); 00355 s.Trim(); 00356 if(s.Length() == untrimmed - 1) 00357 { 00358 //LString supports Trim API 00359 } 00360 00361 s.UpperCase(); 00362 _LIT(KTxtPrintUpperCase,"UpperCase: %S\n"); 00363 gConsole->Printf(KTxtPrintUpperCase, &s); 00364 s.LowerCase(); 00365 _LIT(KTxtPrintLowerCase,"UpperCase: %S\n"); 00366 gConsole->Printf(KTxtPrintLowerCase, &s); 00367 gConsole->Printf(KTxtPressAnyKeyToContinue); 00368 gConsole->Getch(); 00369 /* 00370 The underlying heap allocated buffer is released 00371 automatically when the LString goes out of scope, either 00372 normally or through a leave 00373 */ 00374 } 00375 00376 { 00377 // You can initialize with a MaxLength value 00378 LString s(KMaxFileName); // This operation may leave 00379 if(s.MaxLength() == KMaxFileName) 00380 { 00381 //LString supports MaxLength API 00382 } 00383 00384 /* 00385 And you can dynamically adjust MaxLength later using 00386 SetMaxLengthL() if you want an exact allocated size. 00387 Setting MaxLength() on construction or via SetMaxLengthL() is 00388 exact; calling MaxLength() immediately afterwards is 00389 guaranteed to return exactly the value you specified. 00390 */ 00391 s.SetMaxLengthL(2 * KMaxFileName); 00392 if(s.MaxLength() == 2 * KMaxFileName) 00393 { 00394 //MaxLength is successfully adjusted. 00395 } 00396 00397 /* 00398 Pre-setting MaxLength is important when passing an LString 00399 as a TDes to a library function, because the LString can't 00400 be auto-grown via the TDes API. 00401 */ 00402 00403 } 00404 00405 { 00406 /* 00407 You can initialize from any descriptor (or literal) and the 00408 string data is copied into the LString 00409 */ 00410 LString s(KOne); // From a literal 00411 s += KTwo; 00412 LString half(s.Left(s.Length() / 2)); // Left returns a TPtrC 00413 _LIT(KTxtPrintAllandHalf,"All: %S, Half: %S\n"); 00414 gConsole->Printf(KTxtPrintAllandHalf, &s, &half); 00415 00416 /* 00417 On the other hand, you can initialize from a returned 00418 HBufC* and the LString automatically takes ownership 00419 */ 00420 LString own(AllocateNameL(KTesting)); 00421 _LIT(KTxtOwnedString,"What I own: %S\n"); 00422 gConsole->Printf(KTxtOwnedString, &own); 00423 00424 /* 00425 Following that you can re-assign an HBufC to an existing 00426 string using the assignment operator 00427 taking ownership of the new content. 00428 */ 00429 own = AllocateNameL(KTesting); 00430 00431 /* 00432 Following that you can re-assign an HBufC to an existing 00433 string. The string destroys its original content before 00434 taking ownership of the new content. 00435 */ 00436 own.Assign(AllocateNameL(KTesting)); 00437 00438 /* 00439 The content of one string can similarly be assigned 00440 to another to avoid copying. In this example, the content 00441 is detached from 's' and transfered to 'own'. 00442 */ 00443 own.Assign(s); 00444 00445 /* 00446 The same content transfer can be achieved from an RBuf to a 00447 string. You may need to do this if a legacy method returns 00448 you an RBuf. The RBuf is emptied of its content. 00449 */ 00450 RBuf16 buf; 00451 buf.CreateL(KOne); 00452 own.Assign(buf); 00453 00454 /* 00455 You can also assign a simple text array to a string as its 00456 new buffer. This method initialises the length to zero. 00457 */ 00458 own.Assign((TText*)User::Alloc(24*(TInt)sizeof(TText)), 24); 00459 00460 /* 00461 If the buffer has already been filled with some characters 00462 then you supply the length in this alternative Assign() method. 00463 */ 00464 own.Assign((TText*)User::Alloc(24*(TInt)sizeof(TText)), 12,24); 00465 gConsole->Printf(KTxtPressAnyKeyToContinue); 00466 gConsole->Getch(); 00467 /* 00468 Each Assign() destroys the old content before assuming ownership 00469 of the new. 00470 As usual the last content of the string is destroyed when the 00471 LString goes out of scope 00472 */ 00473 } 00474 00475 { 00476 /* 00477 You can reserve extra free space in preparation for an 00478 operation that adds characters to the string. You may 00479 need to do this when you cannot use any of the auto-buffer 00480 extending LString methods to achieve your objective. 00481 */ 00482 LString s(KOne); 00483 s.ReserveFreeCapacityL(4); 00484 if(s.Length() == 4) 00485 { 00486 //Length() API gives the current length of the string 00487 } 00488 if(s.MaxLength() >= 8) 00489 { 00490 //MaxLength() gives the maximum length supported by the string 00491 } 00492 00493 /* 00494 Almost all the methods that may extend the string buffer, 00495 including the explicit ReserveFreeCapacityL(), but excluding 00496 SetMaxLengthL(), attempt to grow the size exponentially. 00497 The exponential growth pattern is expected to give better 00498 performance at an amortised complexity of O(n) when adding n characters. 00499 If the exponential growth is less than the supplied extra size 00500 then the supplied size is used instead to save time. 00501 The exponential growth is used in anticipation of further additions 00502 to a string. This trades-off speed efficiency for space efficiency. 00503 If required you may be able to swap the oversized buffer for 00504 a more compact one using: 00505 */ 00506 s.Compress(); 00507 if(s.MaxLength() >= 4) 00508 { 00509 //Compress() API is used to compress the unused memory. 00510 } 00511 00512 /* 00513 Resize() attempts to re-allocate a smaller buffer to copy 00514 the content into. If the new memory cannot be allocated then the 00515 original string is left unaffected. 00516 00517 When you have finished using the content of a string you can 00518 get its buffer released without destroying the string itself. 00519 You may want to do this when using member declared strings. 00520 Automatic strings are destroyed when they go out of scope. 00521 */ 00522 s.Reset(); 00523 if(s.Length() == 0) 00524 { 00525 //Buffer of the string is released, hence length is zero. 00526 } 00527 if(s.MaxLength() == 0) 00528 { 00529 //Buffer of the string is released, hence maximum length is zero. 00530 } 00531 00532 } 00533 00534 { 00535 /* 00536 An LString can be passed directly to any function requiring 00537 a const TDesC& 00538 */ 00539 TInt year = 2009; 00540 00541 LString s; 00542 _LIT(KTxtFormatYear1,"Happy New Year %d"); 00543 s.FormatL(KTxtFormatYear1, year); 00544 // InfoPrint() takes a const TDesC& 00545 User::InfoPrint(s); 00546 00547 LString pattern; 00548 _LIT(KTxtFormatYear2,"*Year %d"); 00549 pattern.FormatL(KTxtFormatYear2, year); 00550 // Match() takes a const TDesC& as a pattern 00551 TInt loc = s.Match(pattern); 00552 if(loc == 10) 00553 { 00554 //Match() API is demonstrated successfully. 00555 } 00556 } 00557 00558 { 00559 /* 00560 An LString can be passed directly to any function requiring 00561 a TDes& but care must always be taken to pre-set MaxLength() 00562 since LStrings can't be automatically grown via the TDes 00563 interface 00564 */ 00565 00566 LString s; 00567 /* 00568 Calling GetCurrentPath(s) now would panic because LStrings 00569 are initialized by default to MaxLength 0. Although s is 00570 an LString GetCurrentPath() takes a TDes& and so inside the function 00571 's' behaves as a TDes and would panic with USER 11 if the resulting 00572 new length of s is greater than its maximum length. 00573 */ 00574 if(s.MaxLength() == 0) 00575 { 00576 //LStrings are initialized by default to MaxLength 0 00577 } 00578 00579 /* 00580 Calling SetMaxLengthL() will automatically realloc the 00581 underlying buffer if required, and is guaranteed to leave 00582 MaxLength() equal to the specified value 00583 */ 00584 s.SetMaxLengthL(KMaxFileName); 00585 GetCurrentPath(s); 00586 _LIT(KTxtPrintPath,"Path: %S\n"); 00587 gConsole->Printf(KTxtPrintPath, &s); 00588 if(s == KPath) 00589 { 00590 //String comparison is successful 00591 } 00592 00593 /* 00594 If SetMaxLengthL() adjusts MaxLength() to be lower than the current 00595 Length(), the data is truncated to the new MaxLength() and 00596 Length() set to the new MaxLength(). 00597 */ 00598 s.SetMaxLengthL(s.Length() / 2); 00599 _LIT(KTxtTruncatedPath,"Truncated path: %S\n"); 00600 gConsole->Printf(KTxtTruncatedPath, &s); 00601 if(s.Length() == s.MaxLength()) 00602 { 00603 //String comparison is successful 00604 } 00605 00606 /* 00607 An initial MaxLength() can be specified when constructing an 00608 LString. Note that unlike the default constructor, this 00609 variant allocates and may leave. 00610 */ 00611 LString s2(KMaxFileName); 00612 GetCurrentPath(s2); 00613 gConsole->Printf(KTxtPrintPath, &s2); 00614 if(s2 == KPath) 00615 { 00616 //String comparison is successful 00617 } 00618 00619 /* 00620 Your code and APIs can benefit from LString's auto-growth 00621 behaviour by accepting an LString to fill in as an output 00622 parameter. Using LString rather than TDes parameters means 00623 that the function is able to safely increase the size of the 00624 string as the LString will re-allocate as necessary 00625 */ 00626 LString s3; 00627 // GetCurrentPathString() takes an LString& 00628 GetCurrentPathString(s3); 00629 gConsole->Printf(KTxtPrintPath, &s3); 00630 if(s3 == KPath) 00631 { 00632 //String comparison is successful 00633 } 00634 00635 /* 00636 As a well-defined value class, if you want to, LStrings can 00637 be passed and returned by value. This is relatively 00638 inefficient however due to the amount of copying and heap 00639 reallocation involved. 00640 */ 00641 LString s4(AppendCurrentPathStringL(s3)); 00642 _LIT(KTxtAppendedPath,"Appended path: %S\n"); 00643 gConsole->Printf(KTxtAppendedPath, &s4); 00644 if(s4.Length() == s3.Length() * 2) 00645 { 00646 //String comparison is successful 00647 } 00648 } 00649 00650 { 00651 /* 00652 LStrings can be allocated on the heap if necessary. 00653 Then it can managed as part of an array of string pointers. 00654 */ 00655 TInt n = 5; 00656 LCleanedupHandle<RPointerArray<LString>, TResetAndDestroy> sarray; 00657 00658 for (TInt i = 0; i < n; ++i) 00659 { 00660 LString* s = new(ELeave) LString; 00661 s->FormatL(KTxtFormatString, i); 00662 sarray->Append(s); 00663 } 00664 00665 for (TInt i = 0, n = sarray->Count(); i < n; ++i) 00666 { 00667 LString tmp; 00668 tmp.FormatL(KTxtFormatString, i); 00669 if(tmp == *(*sarray)[i]) 00670 { 00671 00672 } 00673 gConsole->Printf(KTxtPrintString, i, (*sarray)[i]); 00674 } 00675 00676 } 00677 00678 { 00679 /* 00680 Any allocation failure in new(ELeave)LString throws 00681 KErrNoMemory and cleans up fully after itself. 00682 */ 00683 00684 __UHEAP_MARK; 00685 TRAPD(status, new(ELeave) LString(100 * 1024 * 1024)); 00686 if(status == KErrNoMemory) 00687 { 00688 //cleans up after itself fully, there is no need to take any further action. 00689 } 00690 __UHEAP_MARKEND; 00691 } 00692 00693 { 00694 /* 00695 Native C arrays (both heap and stack allocated) of LStrings 00696 also work, although their use is not recommended. 00697 */ 00698 00699 TInt n = 5; 00700 LCleanedupArray<LString> sarray(new(ELeave) LString[n]); 00701 00702 for (TInt i = 0; i < n; ++i) 00703 { 00704 sarray[i].FormatL(KTxtFormatString, i); 00705 } 00706 00707 for (TInt i = 0; i < n; ++i) 00708 { 00709 LString tmp; 00710 tmp.FormatL(KTxtFormatString, i); 00711 if(tmp == sarray[i]) 00712 { 00713 //comparison of strings is successful 00714 } 00715 gConsole->Printf(KTxtPrintString, i, &sarray[i]); 00716 } 00717 00718 } 00719 00720 } 00721 00727 class CManagedUserTwoPhase : public CBase 00728 { 00729 public: 00730 static CManagedUserTwoPhase* NewL(CTicker* aTicker) 00731 { 00732 /* 00733 We can use the resource management utility classes in 00734 two-phase if we want to. 00735 */ 00736 LCleanedupPtr<CManagedUserTwoPhase> self(new(ELeave) CManagedUserTwoPhase); 00737 self->ConstructL(aTicker); 00738 /* 00739 Calling Unmanage() disables cleanup and yields the 00740 previously managed pointer so that it can be safely 00741 returned. 00742 */ 00743 return self.Unmanage(); 00744 } 00745 00746 ~CManagedUserTwoPhase() 00747 { 00748 /* 00749 The iTicker manager will automatically delete the CTicker 00750 The iTimer manager will automatically Close() the RTimer. 00751 */ 00752 } 00753 00754 CTicker& Ticker() 00755 { 00756 // If we dereference the management object we get a CTicker&. 00757 return *iTicker; 00758 } 00759 00760 RTimer& Timer() 00761 { 00762 // If we dereference the management object we get an RTimer&. 00763 return *iTimer; 00764 } 00765 00766 private: 00767 00768 virtual void ConstructL(CTicker* aTicker) 00769 { 00770 // Take ownership and manage aTicker. 00771 iTicker = aTicker; 00772 00773 // Note use of -> to indirect through the management wrapper. 00774 iTimer->CreateLocal() OR_LEAVE; 00775 } 00776 00777 CManagedUserTwoPhase() 00778 { 00779 /* 00780 Everything interesting happens in ConstructL() in this 00781 version. 00782 00783 Default initialization of the iName LString does not 00784 allocate a heap buffer, and so cannot leave. As long as 00785 initialization is deferred to ConstructL(), LStrings can be 00786 used safely with two-phase construction. 00787 */ 00788 } 00789 00790 private: 00791 // We have to use LManagedXxx for fields, not LCleanedupXxx 00792 LManagedPtr<CTicker> iTicker; 00793 LManagedHandle<RTimer> iTimer; 00794 }; 00795 00808 class CManagedUserSinglePhase : public CBase 00809 { 00810 public: 00811 /* 00812 This macro is necessary to ensure cleanup is correctly handled 00813 in the event that a constructor may leave beneath a call to 00814 new(ELeave) 00815 */ 00816 CONSTRUCTORS_MAY_LEAVE 00817 00818 static CManagedUserSinglePhase* NewL(CTicker* aTicker) 00819 { 00820 return new(ELeave) CManagedUserSinglePhase(aTicker); 00821 } 00822 00823 ~CManagedUserSinglePhase() 00824 { 00825 /* 00826 The iTicker manager destructor will automatically Zap() the CTicker. 00827 The iTimer manager destructor will automatically Close() the RTimer. 00828 */ 00829 } 00830 00831 CTicker& Ticker() 00832 { 00833 // If we dereference the management object we get a CTicker&. 00834 return *iTicker; 00835 } 00836 00837 RTimer& Timer() 00838 { 00839 // If we dereference the management object we get an RTimer&. 00840 return *iTimer; 00841 } 00842 00843 private: 00844 CManagedUserSinglePhase(CTicker* aTicker) 00845 /* 00846 Take ownership and manage aTicker. Note that initialization 00847 of the LManagedXxx classes does not actually leave, but 00848 initialization of the LCleanedupXxx classes can. 00849 */ 00850 : iTicker(aTicker) 00851 { 00852 /* 00853 If iTicker initialization is successful but the constructor 00854 then goes on to leave later, iTicker (like all fields fully 00855 constructed at the point of a leave in a constructor) will 00856 be destructed, and the manager will cleanup the CTicker. 00857 00858 Note use of -> to indirect through the management wrapper. 00859 */ 00860 iTimer->CreateLocal(); 00861 00862 // Likewise if we leave here, both iTicker and iTimer will 00863 // undergo managed cleanup. 00864 MaybeLeave(); 00865 } 00866 00867 private: 00868 // We have to use LManagedXxx for fields, not LCleanedupXxx. 00869 LManagedPtr<CTicker, TTickerZapStrategy> iTicker; 00870 LManagedHandle<RTimer> iTimer; 00871 }; 00872 00873 //Class definition of trivial R-Class 00874 class RSimple 00875 { 00876 public: 00877 00878 RSimple(){iData = NULL;} 00879 00880 //Open function sets value 00881 void OpenL(TInt aValue) 00882 { 00883 iData = new(ELeave) TInt(aValue); 00884 } 00885 00886 //Cleanup function – frees resource 00887 void Close() 00888 { 00889 delete iData; 00890 iData = NULL; 00891 } 00892 00893 //Cleanup function – frees resource 00894 void Free() 00895 { 00896 delete iData; 00897 iData = NULL; 00898 } 00899 00900 //Cleanup function – frees resource 00901 void ReleaseData() 00902 { 00903 delete iData; 00904 iData = NULL; 00905 } 00906 00907 //static cleanup function – frees aRSimple resources 00908 static void Cleanup(TAny* aRSimple) 00909 { 00910 static_cast<RSimple*>(aRSimple)->Close(); 00911 } 00912 00913 00914 private: 00915 TInt* iData; 00916 00917 }; 00918 00919 00926 DEFINE_CLEANUP_FUNCTION(RSimple, ReleaseData); 00927 00928 00929 void WalkthroughManagedL() 00930 { 00931 _LIT(KTxtOption2,"Option2: Object creation and resource management using EUser high level library\n"); 00932 gConsole->Printf(KTxtOption2); 00933 { 00934 // Trivially exercise the manager-using classes defined above. 00935 CTicker* ticker1 = new(ELeave) CTicker; 00936 LCleanedupPtr<CManagedUserTwoPhase> one(CManagedUserTwoPhase::NewL(ticker1)); 00937 if(&one->Ticker() == ticker1) 00938 { 00939 _LIT(KTxtLCleanedupPtrDemo1,"Creating an instance of CTicker using LCleanedupPtr\n"); 00940 gConsole->Printf(KTxtLCleanedupPtrDemo1); 00941 } 00942 one->Timer().Cancel(); // Just to check we can get at it 00943 00944 CTicker* ticker2 = new(ELeave) CTicker; 00945 LCleanedupPtr<CManagedUserSinglePhase> two(CManagedUserSinglePhase::NewL(ticker2)); 00946 if(&two->Ticker() == ticker2) 00947 { 00948 _LIT(KTxtLCleanedupPtrDemo2,"Creating second instance of CTicker using LCleanedupPtr\n"); 00949 gConsole->Printf(KTxtLCleanedupPtrDemo2); 00950 } 00951 two->Timer().Cancel(); // Just to check we can get at it 00952 _LIT(KTxtLCleanedupPtr,"Both instances are automatically deleted as we go out of scope\n"); 00953 gConsole->Printf(KTxtLCleanedupPtr); 00954 gConsole->Printf(KTxtPressAnyKeyToContinue); 00955 gConsole->Getch(); 00956 } 00957 00958 // Always use LCleanedupXxx for locals, not LManagedXxx 00959 00960 { 00961 /* 00962 Behind the scenes the LCleanedupXxx constructors push a 00963 cleanup item onto the cleanup stack and so may leave. If 00964 there is a leave during construction, the supplied pointer 00965 will still get cleaned up. 00966 */ 00967 LCleanedupPtr<CTicker> t(new(ELeave) CTicker); 00968 00969 /* 00970 We can access CTicker's members via the management object 00971 using -> 00972 */ 00973 t->Tick(); 00974 t->Tock(); 00975 if(t->iTicks == t->iTocks) 00976 { 00977 _LIT(KTxtLCleanedupPtrDemo3,"CTicker members access using LCleanedupPtr is successful\n"); 00978 gConsole->Printf(KTxtLCleanedupPtrDemo3); 00979 gConsole->Printf(KTxtPressAnyKeyToContinue); 00980 gConsole->Getch(); 00981 } 00982 00983 /* 00984 We can get at a reference to the managed object using * 00985 when we need to, e.g. if we need to pass it to a function. 00986 */ 00987 RegisterTicker(*t); // Takes a CTicker& 00988 00989 /* 00990 If some unfriendly interface needs a pointer rather than a 00991 ref, we have a couple of options. 00992 */ 00993 RegisterTickerPtr(&*t); // Takes a CTicker* 00994 RegisterTickerPtr(t.Get()); // Takes a CTicker* 00995 00996 /* 00997 Note the use of . in t.Get() above; this distinguishes 00998 operations on the managing type from operations on the 00999 managed object. 01000 01001 When the management object goes out of scope, either 01002 normally or as the result of a leave, the managed object is 01003 automatically deleted. 01004 */ 01005 } 01006 01007 { 01008 /* 01009 Sometimes you need to protect something temporarily before 01010 transferring ownership e.g. by returning the pointer or 01011 passing it to a function that takes ownership. 01012 */ 01013 01014 LCleanedupPtr<CTicker> t(new(ELeave) CTicker); 01015 01016 // Protected while we do this 01017 MaybeLeave(); 01018 01019 /* 01020 But now we want to hand it off, so we use Unmanage() to 01021 both return a pointer and break the management link 01022 */ 01023 TakeTickerOwnership(t.Unmanage()); 01024 01025 /* 01026 Now when it goes out of scope, no cleanup action is 01027 performed. 01028 */ 01029 } 01030 01031 { 01032 /* 01033 If needed, it is possible to reuse a manager by using = to 01034 assign it a new managed object. 01035 */ 01036 01037 // Not managing anything to start with 01038 LCleanedupPtr<CTicker> t; 01039 if(t.Get() == NULL) 01040 { 01041 //Successfully initialised to NULL 01042 } 01043 if(&*t == NULL) 01044 { 01045 //CTicker* value is also NULL 01046 } 01047 01048 for (TInt i = 0; i < 10; ++i) 01049 { 01050 /* 01051 If an object is already being managed, it is cleaned up 01052 before taking ownership of the new object. 01053 */ 01054 t = new(ELeave) CTicker; 01055 } 01056 /* 01057 We're left owning the final ticker instance, all prior 01058 instances having been automatically deleted. 01059 */ 01060 } 01061 01062 { 01063 // If you have stateful code where a pointer can sometimes be NULL. 01064 LCleanedupPtr<CTicker> t(new(ELeave) CTicker); 01065 01066 // Does t refer to NULL? 01067 if (!t) 01068 { 01069 _LIT(KTxtNull,"LCleanedupPtr object refers to Null\n" ); 01070 gConsole->Printf(KTxtNull); 01071 } 01072 01073 t = NULL; // Also releases the currently managed CTicker 01074 01075 // Does t refer to a non-NULL pointer? 01076 if (t) 01077 { 01078 _LIT(KTxtNonNull,"LCleanedupPtr object refers to Non Null pointer\n" ); 01079 gConsole->Printf(KTxtNonNull); 01080 } 01081 } 01082 01083 { 01084 // LCleanedupPtr uses delete to cleanup by default, but alternative cleanups can be specified 01085 01086 // We just want to free this one and not invoke the destructor 01087 LCleanedupPtr<CTicker, TPointerFree> t(static_cast<CTicker*>(User::AllocL(sizeof(CTicker)))); 01088 01089 // Now User::Free() is called when t goes out of scope 01090 } 01091 01092 { 01093 /* 01094 As well as the stock options, custom cleanup policies can 01095 also be defined. See above for the definition of 01096 TTickerZap. 01097 */ 01098 LCleanedupPtr<CTicker, TTickerZapStrategy> t(new(ELeave) CTicker); 01099 01100 // Now Zap() is called on the CTicker instance when t goes out of scope 01101 } 01102 01103 { 01104 /* 01105 LCleanedupHandle is very similar in behaviour to 01106 LCleanedupPtr, the main difference being that it can define 01107 and contain its own instance of a handle rather than 01108 being supplied one. 01109 */ 01110 LCleanedupHandle<RTimer> t; 01111 01112 // Again, access to managed handle members is via -> 01113 t->CreateLocal() OR_LEAVE; 01114 t->Cancel(); 01115 01116 //We can get a reference to the handle for passing to functions using * 01117 RegisterTimer(*t); 01118 01119 /* 01120 When the management object goes out of scope, either 01121 normally or as the result of a leave, the managed object is 01122 automatically cleanup by calling Close() on it. 01123 */ 01124 } 01125 01126 { 01127 /* 01128 LCleanedupHandle calls Close() by default, but alternative 01129 cleanups can be specified. 01130 01131 We want this RPointerArray cleanup with with 01132 ResetAndDestroy instead of Close(). 01133 */ 01134 LCleanedupHandle<RPointerArray<HBufC>, TResetAndDestroy> array; 01135 for (TInt i = 0; i < 10; ++i) 01136 { 01137 array->AppendL(HBufC::NewL(5)); 01138 } 01139 01140 //Now when array goes out of scope, ResetAndDestroy is called to clean it up. 01141 } 01142 01143 { 01144 /* 01145 As well as the stock options, custom cleanup policies can 01146 also be defined. See above for the definition of TCancelClose. 01147 */ 01148 LCleanedupHandle<RTimer, TCancelClose> t; 01149 t->CreateLocal(); 01150 01151 // Now Cancel() followed by Close() are called when t goes out of scope 01152 } 01153 01154 01155 { 01156 /* 01157 LCleanedupHandleRef calls Close() by default, but alternative 01158 cleanups can be specified. 01159 01160 We want this RPointerArray cleanup with 01161 ResetAndDestroy instead of Close(). 01162 */ 01163 RPointerArray<HBufC> rar; 01164 // calls to functions that cannot leave here 01165 rar.Append(HBufC::NewL(5)); 01166 rar.Append(HBufC::NewL(5)); 01167 01168 01169 LCleanedupRef<RPointerArray<HBufC>, TResetAndDestroy> array(rar); 01170 // calls to functions that could leave here 01171 for (TInt i = 0; i < 10; ++i) 01172 { 01173 array->AppendL(HBufC::NewL(5)); 01174 } 01175 01176 // Now when array goes out of scope, ResetAndDestroy is called to clean it up 01177 } 01178 01179 { 01180 /* 01181 Never mix direct cleanup stack API calls with management 01182 class use within the same function, because their 01183 interaction can be confusing and counter-intuitive. Avoid 01184 the use of LC methods that leave objects on the cleanup 01185 stack, and use L methods instead. 01186 01187 If a badly-behaved API were to offer only an LC variant, 01188 you would have to use it as follows 01189 */ 01190 HBufC* raw = HBufC::NewLC(5); 01191 // Must pop immediately to balance the cleanup stack, before instantiating the manager 01192 CleanupStack::Pop(); 01193 LCleanedupPtr<HBufC> wrapped(raw); 01194 01195 /* 01196 Never do this: 01197 LCleanedupPtr<HBufC> buf(HBufC::NewLC(5)); 01198 CleanupStack::Pop(); 01199 because the manager will be popped (having been pushed 01200 last), not the raw buf pointer as you might have hoped 01201 01202 A cleaner alternative may be to write your own L function 01203 wrapper around the LC function supplied. 01204 01205 Luckily this situation (an LC method without a 01206 corresponding L method) is rare in practice. 01207 */ 01208 } 01209 01210 { 01211 // Although rarely used on the Symbian platform, C++ arrays are supported with a custom management class 01212 LCleanedupArray<CTicker> array(new CTicker[5]); 01213 01214 // The array is cleaned up with delete[] on scope exit 01215 } 01216 01217 { 01218 /* 01219 Although most cases are best covered by applying custom 01220 cleanup policies to the management classes already 01221 described, there is also a general TCleanupItem style 01222 cleanup option. 01223 */ 01224 TAny* data = NULL; // But could be anything 01225 LCleanedupGuard guard1(BespokeCleanupFunction, data); 01226 // On scope exit BespokeCleanupFunction() is called on data. 01227 01228 LCleanedupGuard guard2(BespokeCleanupFunction, data); 01229 // But cleanup can also be disabled in this case, as follows: 01230 guard2.Dismiss(); 01231 } 01232 01233 { 01234 LCleanedupHandle<RFs> managedFs; 01235 managedFs->Connect(); 01236 //default cleanup strategy is to call RFs::Close() on scope exit; 01237 } 01238 01239 { 01240 LCleanedupHandle<RSimple, TFree> simple; 01241 simple->OpenL(23); 01242 //Specified cleanup strategy is to call RSimple::Free() on scope exit; 01243 } 01244 01245 /* 01246 Because the DEFINE_CLEANUP_FUNCTION is defined above, the default 01247 cleanup function for RSimple is RSimple::ReleaseData() rather than 01248 RSimple::Close() 01249 */ 01250 { 01251 LCleanedupHandle<RSimple> simple; 01252 simple->OpenL(23); 01253 //Custom cleanup strategy is to call RSimple::ReleaseData() on scope exit 01254 } 01255 01256 { 01257 RSimple simple; 01258 01259 //The RSimple class above defines a static cleanup function 01260 //RSimple::Cleanup(). 01261 LCleanedupGuard guard(RSimple::Cleanup, &simple); 01262 01263 simple.OpenL(10); 01264 01265 //On scope exit RSimple::Cleanup() is called passing &simple. 01266 } 01267 } 01268 01269 void WalkthroughUsageL() 01270 { 01271 _LIT(KTxtOption3,"Option3: Memory used by EUser high level classes\n"); 01272 gConsole->Printf(KTxtOption3); 01273 RFile file; 01274 01275 _LIT(KTxtSizeofRFile,"Size of RFile = %d\n"); 01276 gConsole->Printf(KTxtSizeofRFile, sizeof(file)); 01277 01278 LCleanedupHandle<RFile> cFile; 01279 01280 _LIT(KTxtSizeofLCleanedupHandleRFile,"Size of LCleanedupHandle<RFile> = %d\n"); 01281 gConsole->Printf(KTxtSizeofLCleanedupHandleRFile, sizeof(cFile)); 01282 gConsole->Printf(KTxtPressAnyKeyToContinue); 01283 gConsole->Getch(); 01284 01285 LCleanedupRef<RFile> crFile(file); 01286 _LIT(KTxtSizeofLCleanedupRefRFile,"Size of LCleanedupRef<RFile> = %d\n"); 01287 gConsole->Printf(KTxtSizeofLCleanedupRefRFile, sizeof(crFile)); 01288 gConsole->Printf(KTxtPressAnyKeyToContinue); 01289 gConsole->Getch(); 01290 01291 CTicker* tracker = new(ELeave) CTicker; 01292 _LIT(KTxtSizeofCTracker,"Size of CTracker* = %d\n"); 01293 gConsole->Printf(KTxtSizeofCTracker, sizeof(tracker)); 01294 gConsole->Printf(KTxtPressAnyKeyToContinue); 01295 gConsole->Getch(); 01296 01297 LCleanedupPtr<CTicker> cTracker(tracker); 01298 _LIT(KTxtSizeofLCleanedupHandleCTicker,"Size of LCleanedupPtr<CTicker> = %d\n"); 01299 gConsole->Printf(KTxtSizeofLCleanedupHandleCTicker, sizeof(LCleanedupPtr<CTicker>)); 01300 gConsole->Printf(KTxtPressAnyKeyToContinue); 01301 gConsole->Getch(); 01302 } 01303 01304 TInt TestL() 01305 { 01306 gConsole=Console::NewL(KTxtExample,TSize(KConsFullScreen,KConsFullScreen)); 01307 CleanupStack::PushL(gConsole); 01308 gConsole->Printf(KTxtExample); 01309 gConsole->Printf(KTxtPressAnyKeyToContinue); 01310 gConsole->Getch(); 01311 WalkthroughStringsL(); 01312 gConsole->Printf(KTxtPressAnyKeyToContinue); 01313 gConsole->Getch(); 01314 WalkthroughManagedL(); 01315 gConsole->Printf(KTxtPressAnyKeyToContinue); 01316 gConsole->Getch(); 01317 WalkthroughUsageL(); 01318 _LIT(KTxtPressAnyKeyToExit,"\nPress any key to exit"); 01319 gConsole->Printf(KTxtPressAnyKeyToExit); 01320 gConsole->Getch(); 01321 CleanupStack::PopAndDestroy(gConsole); // delete the gConsole 01322 return KErrNone; 01323 } 01324 01325 TInt E32Main() 01326 { 01327 __UHEAP_MARK; 01328 CTrapCleanup* cleanup=CTrapCleanup::New(); // Create clean-up stack. 01329 TInt status; 01330 if(cleanup!=NULL) 01331 { 01332 TRAP(status, TestL()); 01333 __ASSERT_ALWAYS(!status,User::Panic(KTxtExample,status)); 01334 } 01335 delete cleanup; // Delete clean-up stack. 01336 __UHEAP_MARKEND; 01337 01338 return status; 01339 } 01340 01341 01342 // eof
Copyright ©2010 Nokia Corporation and/or its subsidiary(-ies).
All rights
reserved. Unless otherwise stated, these materials are provided under the terms of the Eclipse Public License
v1.0.