os/ossrv/lowlevellibsandfws/genericusabilitylib/example/src/euserhl_walkthrough.cpp
First public contribution.
1 // Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
2 // All rights reserved.
3 // This component and the accompanying materials are made available
4 // under the terms of "Eclipse Public License v1.0"
5 // which accompanies this distribution, and is available
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
23 // Note: Methods are defined inline within classes here simply to make
24 // the code shorter, keep related code closer together, and hopefully
25 // make things easier to follow.
27 RTest test(_L("EuserHl Walkthrough"));
29 // Some dummy methods and data used in the walkthroughs below
31 _LIT(KPath, "c:\\a\\b\\c");
34 _LIT(KTesting, "Testing ");
38 // Some code that may leave
41 HBufC* AllocateNameL(const TDesC& aDes)
46 void ReadToMax(TDes& aDes)
52 void GetCurrentPath(TDes& aDes)
57 void GetCurrentPathStringL(LString& aString)
59 aString = L"c:\\a\\b\\c"; // Will auto-grow if necessary, may leave
62 LString AppendCurrentPathStringL(LString aString)
64 return aString+= L"c:\\a\\b\\c";
67 class CTicker : public CBase
70 void Tick() { ++iTicks; }
71 void Tock() { ++iTocks; }
73 void Zap() { delete this; }
80 // Defines a custom pointer cleanup policy that calls the Zap member
81 class TTickerZapStrategy
84 static void Cleanup(CTicker* aPtr)
86 // The general template/class scaffolding remains the same
87 // for all custom cleanups, just this cleanup body varies
89 test.Printf(_L("Zapped CTicker\n"));
93 void RegisterTicker(CTicker& aTicker)
98 void RegisterTickerPtr(CTicker* aTicker)
103 void TakeTickerOwnership(CTicker* aTicker)
108 void RegisterTimer(RTimer& aTimer)
113 // Defines a custom handle cleanup policy that calls Cancel then Close
118 static void Cleanup(T* aHandle)
120 // The general template/class scaffolding remains the same
121 // for all custom cleanups, just this cleanup body varies
124 test.Printf(_L("Cancel Closed RTimer\n"));
128 void BespokeCleanupFunction(TAny* aData)
131 test.Printf(_L("BespokeCleanupFunction\n"));
134 // The walkthroughs themselves
136 // This class demonstrates the use of an embedded LString in the
137 // conventional Symbian two-phase construction pattern. We've chosen
138 // to implement the temporary leave protection in NewL in terms of
139 // LCleanedupPtr instead of the the CleanupStack API in this example.
140 class CStringUserTwoPhase : public CBase
143 static CStringUserTwoPhase* NewL(const TDesC& aName)
145 // We can use the resource management utility classes in
146 // two-phase if we want to
147 LCleanedupPtr<CStringUserTwoPhase> self(new(ELeave) CStringUserTwoPhase);
148 self->ConstructL(aName);
149 // Calling Unmanage() disables cleanup and yields the
150 // previously managed pointer so that it can be safely
152 return self.Unmanage();
155 virtual void ConstructL(const TDesC& aName)
157 // This assignment may leave if LString fails to allocate a
158 // heap buffer large enough to hold the data in aName
162 ~CStringUserTwoPhase()
164 // The iName LString cleans up after itself automatically
169 // We can just return an LString directly as a const TDesC
174 CStringUserTwoPhase()
176 // Everything interesting happens in ConstructL in this
179 // Default initialization of the iName LString does not
180 // allocate a heap buffer, and so cannot leave. As long as
181 // initialization is deferred to ConstructL, LStrings can be
182 // used safely with two-phase construction.
189 // This class demonstrates the use of an embedded LString in the
190 // single-phase construction pattern, where a leave-safe constructor
191 // fully initializes the object.
193 // Note that where a class's constructor forms part of its exported
194 // public or protected contract, switching from a non-leaving to a
195 // potentially leaving constructor would be a BC break. On the other
196 // hand, if instantiation is entirely encapsulated within factory
197 // functions like NewL, there is no such BC restriction.
198 class CStringUserSinglePhase : public CBase
201 // This macro is necessary to ensure cleanup is correctly handled
202 // in the event that a constructor may leave beneath a call to
204 CONSTRUCTORS_MAY_LEAVE
206 static CStringUserSinglePhase* NewL(const TDesC& aName)
208 return new(ELeave) CStringUserSinglePhase(aName);
211 ~CStringUserSinglePhase()
213 // The iName LString cleans up after itself automatically
218 // We can just return an LString directly as a const TDesC
223 CStringUserSinglePhase(const TDesC& aName)
224 // This initialization of iName may leave because LString
225 // needs to allocate a heap buffer to copy the aName string
229 // If iName initialization is successful but the constructor
230 // then goes on to leave later, iName (like all fields fully
231 // constructed at the point of a leave in a constructor) will
232 // be destructed, and so clean up after itself
241 void WalkthroughStringsL()
245 // Trivially exercise the LString using classes defined above
247 LCleanedupPtr<CStringUserTwoPhase> one(CStringUserTwoPhase::NewL(KOne));
248 test.Printf(_L("Single phase name: %S\n"), &one->Name());
250 LCleanedupPtr<CStringUserSinglePhase> two(CStringUserSinglePhase::NewL(KTwo));
251 test.Printf(_L("Two phase name: %S\n"), &two->Name());
253 // Both instances are automatically deleted as we go out of scope
257 // A default constructed LString starts empty, doesn't
258 // allocate any memory on the heap, and therefore the
259 // following cannot leave
262 // But it will grow on demand if you assign to it, so it has
263 // enough space to hold the copied string data, and so
264 // assignment may leave
267 // Similarly if you append to it with the leaving variant of
268 // Append, AppendL, if may grow on demand
271 // The += operator for LString also maps to AppendL
274 // You can also use new leaving format methods that also grow
276 s.AppendFormatL(KTesting);
278 // This general style of use of LString may be preferable to
279 // typical descriptor use for a number of reasons e.g. it
280 // avoids the common temptation to set an artificial maximum
281 // buffer size; it avoids massive conservative over-allocation
282 // when the average case length of a string is far less than
283 // the worst-case maximum; it will not surprise you (compared
284 // to the alternative of a large stack-allocated TBuf) by
285 // triggering stack overflow.
287 // An LString can be printed the same way as any descriptor
288 test.Printf(_L("Value: %S\n"), &s);
290 // An LString supports all TDesC and TDes methods
291 // LString findToken(L"Two ");
292 test(s.Find(L"Two ") == 4);
294 // LString matchPattern(L"*Two* ");
295 test(s.Match(L"*Two*") == 4);
296 test(s.Match(L"*T?o*") == 4);
298 // LString compare(L"some string");
299 test(s.Compare(L"One Two Three Testing ") == 0);
300 test(s.Compare(L"One Two Three Testing! ") < 0);
301 test(s.Compare(L"One Two Testing ") > 0);
303 // also LString ==,!=,>,<,<=,>=(L"some string");
304 test(s == L"One Two Three Testing ");
305 test(s < L"One Two Three Testing! ");
306 test(s > L"One Two Testing ");
307 test(s != L"not equal");
309 // An LString supports all TDesC and TDes operators
310 test(s[4] == TChar('T'));
312 TInt untrimmed = s.Length();
314 test(s.Length() == untrimmed - 1);
317 test.Printf(_L("UpperCase: %S\n"), &s);
319 test.Printf(_L("LowerCase: %S\n"), &s);
321 // The underlying heap allocated buffer is released
322 // automatically when the LString goes out of scope, either
323 // normally or through a leave
326 // Copy, Append,Insert,Replace,Justify the same way as TDesC and TDes
329 // Copies data into this 8-bit string descriptor, replacing any existing
330 // data, and expanding its heap buffer to accommodate if necessary.
331 // leaves on not being able to accomodate the new content
332 // both AssignL and += use CopyL internally
333 s.CopyL(L"new way of dealing with strings");
334 s.CopyUCL(L"new way of dealing with strings");
335 test(s == L"NEW WAY OF DEALING WITH STRINGS");
337 // Insert data into this descriptor.
338 // The length of this descriptor is changed to reflect the extra data.
339 // This leaving variant of the standard, non-leaving descriptor method
340 // differs in that this operation may cause the string descriptor's heap
341 // buffer to be reallocated in order to accommodate the new data. As a
342 // result, MaxLength() and Ptr() may return different values afterwards,
343 // and any existing raw pointers to into the descriptor data may be
345 s.CopyL(L"Some Content Can Be Into This String");
346 s.InsertL(20,L"Inserted ");
347 test(s == L"Some Content Can Be Inserted Into This String");
349 // Replace data in this descriptor.
350 // The specified length can be different to the length of the replacement data.
351 // The length of this descriptor changes to reflect the change of data.
352 // This leaving variant of the standard, non-leaving descriptor method
353 // differs in that this operation may cause the string descriptor's heap
354 // buffer to be reallocated in order to accommodate the new data. As a
355 // result, MaxLength() and Ptr() may return different values afterwards,
356 // and any existing raw pointers to into the descriptor data may be
358 s.CopyL(L"Some Content Can Be Decalper");
359 s.ReplaceL(20,8,L"Replaced");
360 test(s == L"Some Content Can Be Replaced");
362 // Append data onto the end of this descriptor's data.
363 // The length of this descriptor is incremented to reflect the new content.
364 // This leaving variant of the standard, non-leaving descriptor method
365 // differs in that this operation may cause the string descriptor's heap
366 // buffer to be reallocated in order to accommodate the new data. As a
367 // result, MaxLength() and Ptr() may return different values afterwards,
368 // and any existing raw pointers to into the descriptor data may be
370 s.CopyL(L"Try appending ");
371 s.AppendL(L"Try appending some more",3);
372 test(s == L"Try appending Try");
374 // Copy data into this descriptor and justifies it, replacing any existing data.
375 // The length of this descriptor is set to reflect the new data.
376 // The target area is considered to be an area of specified width positioned at
377 // the beginning of this descriptor's data area. Source data is copied into, and
378 // aligned within this target area according to the specified alignment
380 // If the length of the target area is larger than the length of the source, then
381 // spare space within the target area is padded with the fill character.
382 // This leaving variant of the standard, non-leaving descriptor method
383 // differs in that this operation may cause the string descriptor's heap
384 // buffer to be reallocated in order to accommodate the new data. As a
385 // result, MaxLength() and Ptr() may return different values afterwards,
386 // and any existing raw pointers to into the descriptor data may be
388 s.CopyL(L"Justified");
389 s.JustifyL(L"Just",9,ERight,'x');
390 test(s == L"xxxxxJust");
392 // Append data onto the end of this descriptor's data and justifies it.
393 // The source of the appended data is a memory location.
394 // The target area is considered to be an area of specified width, immediately
395 // following this descriptor's existing data. Source data is copied into, and
396 // aligned within, this target area according to the specified alignment instruction.
397 // If the length of the target area is larger than the length of the source,
398 // then spare space within the target area is padded with the fill character.
399 // This leaving variant of the standard, non-leaving descriptor method
400 // differs in that this operation may cause the string descriptor's heap
401 // buffer to be reallocated in order to accommodate the new data. As a
402 // result, MaxLength() and Ptr() may return different values afterwards,
403 // and any existing raw pointers to into the descriptor data may be
406 s.AppendJustifyL(L"Two Three",3,7,ERight,'x');
407 test(s == L"One xxxxTwo" );
411 // You can initialize with a MaxLength value
412 LString s(KMaxFileName); // This operation may leave
413 test(s.MaxLength() == KMaxFileName);
415 // And you can dynamically adjust MaxLength later using
416 // SetMaxLengthL if you want an exact allocated size
417 // Setting MaxLength on construction or via SetMaxLengthL is
418 // exact; calling MaxLength() immediately afterwards is
419 // guaranteed to return exactly the value you specified
420 s.SetMaxLengthL(2 * KMaxFileName);
421 test(s.MaxLength() == 2 * KMaxFileName);
423 // Pre-setting MaxLength is important when passing an LString
424 // as a TDes to a library function, because the LString can't
425 // be auto-grown via the TDes API
430 // You can initialize from any descriptor/literal/[wide]character string and the
431 // string data is copied into the LString
432 LString s(L"One "); // From a character string
434 LString half(s.Left(s.Length() / 2)); // Left returns a TPtrC
435 test.Printf(_L("All: %S, Half: %S\n"), &s, &half);
437 // On the other hand, you can initialize from a returned
438 // HBufC* and the LString automatically takes ownership
439 LString own(AllocateNameL(KTesting));
440 test.Printf(_L("What I own: %S\n"), &own);
442 // Following that you can re-assign an HBufC to an existing
443 // string using the assignment operator
444 // taking ownership of the new content.
445 own = AllocateNameL(KTesting);
447 // Following that you can re-assign an HBufC to an existing
448 // string. The string destroys its original content before
449 // taking ownership of the new content.
450 own.Assign(AllocateNameL(KTesting));
452 // The content of one string can similarly be assigned
453 // to another to avoid copying. In this example, the content
454 // is detached from 's' and transfered to 'own'.
457 // The same content transfer can be achieved from an RBuf to a
458 // string. You may need to do this if a legacy method returns
459 // you an RBuf. The RBuf is emptied of its content.
464 // You can also assign a simple text array to a string as its
465 // new buffer. This method initialises the length to zero.
466 own.Assign((TText*)User::Alloc(24*(TInt)sizeof(TText)), 24);
468 // If the buffer has already been filled with some characters
469 // then you supply the length in this alternative Assign method.
470 own.Assign((TText*)User::Alloc(24*(TInt)sizeof(TText)), 12,24);
472 // Each Assign destroys the old content before assuming ownership
474 // As usual the last content of the string is destroyed when the
475 // LString goes out of scope
479 // You can reserve extra free space in preparation for an
480 // operation that adds characters to the string. You may
481 // need to do this when you cannot use any of the auto-buffer
482 // extending LString methods to achieve your objective.
484 s.ReserveFreeCapacityL(4);
485 test(s.Length() == 4);
486 test(s.MaxLength() >= 8);
488 // Almost all the methods that may extended the string buffer,
489 // including the explicit ReserveFreeCapacityL, but excluding
490 // SetMaxLengthL, attempt to grow the size exponentially.
491 // The Exponential growth pattern is expected to give better
492 // performance at an amortised complexity of O(n) when adding n characters.
493 // If the exponential growth is less than the supplied extra size
494 // then the supplied size is used instead to save time.
495 // The exponential growth is used in anticipation of further additions
496 // to a string. This trades-off speed efficiency for space efficiency.
497 // If required you may be able to swap the oversized buffer for
498 // a more compact one using:
500 test(s.MaxLength() >= 4); //note indefinite test
502 // Resize attempts to re-allocate a smaller buffer to copy
503 // the content into. If the new memory cannot be allocated then the
504 // original string is left unaffected.
506 // When you have finished using the content of a string you can
507 // get its buffer released without destroying the string itself.
508 // You may want to do this when using member declared strings.
509 // Automatic strings are destroyed when they go out of scope.
511 test(s.Length() == 0);
512 test(s.MaxLength() == 0);
517 // An LString can be passed directly to any function requiring
522 s.FormatL(_L("Happy New Year %d"), year);
523 // InfoPrint takes a const TDesC&
527 pattern.FormatL(_L("*Year %d"), year);
528 // Match takes a const TDesC& as a pattern
529 TInt loc = s.Match(pattern);
534 // An LString can be passed directly to any function requiring
535 // a TDes& but care must always be taken to pre-set MaxLength
536 // since LStrings can't be automatically grown via the TDes
540 // Calling GetCurrentPath(s) now would panic because LStrings
541 // are initialized by default to MaxLength 0. Although s is
542 // an LString GetCurrentPath takes a TDes& and so inside the function
543 // s behaves as a TDes and would panic with USER 11 if the resulting
544 // new length of s is greater than its maximum length.
545 test(s.MaxLength() == 0);
547 // Calling SetMaxLengthL will automatically realloc the
548 // underlying buffer if required, and is guaranteed to leave
549 // MaxLength() equal to the specified value
550 s.SetMaxLengthL(KMaxFileName);
552 //LString pathString(L"c:\\a\\b\\c");
553 test.Printf(_L("Path: %S\n"), &s);
554 test(s == L"c:\\a\\b\\c");
556 // If SetMaxLengthL adjusts MaxLength lower than the current
557 // Length, the data is truncated to the new MaxLength and
558 // Length set to the new MaxLength
559 s.SetMaxLengthL(s.Length() / 2);
560 test.Printf(_L("Truncated path: %S\n"), &s);
561 test(s.Length() == s.MaxLength());
563 // An initial MaxLength can be specified when constructing an
564 // LString. Note that unlike the default constructor, this
565 // variant allocates and may leave.
566 LString s2(KMaxFileName);
568 test.Printf(_L("Path: %S\n"), &s2);
569 test(s2 == L"c:\\a\\b\\c");
571 // Your code and APIs can benefit from LString's auto-growth
572 // behaviour by accepting an LString to fill in as an output
573 // parameter. Using LString rather than TDes parameters means
574 // that the function is able to safely increase the size of the
575 // string as the LString will re-allocate as necessary
577 // GetCurrentPathStringL takes an LString&
578 GetCurrentPathStringL(s3);
579 test.Printf(_L("Path: %S\n"), &s3);
580 test(s3 == L"c:\\a\\b\\c");
582 // As a well-defined value class, if you want to, LStrings can
583 // be passed and returned by value. This is relatively
584 // inefficient however due to the amount of copying and heap
585 // reallocation involved.
586 LString s4(AppendCurrentPathStringL(s3));
587 test.Printf(_L("Appended path: %S\n"), &s4);
588 test(s4.Length() == s3.Length() * 2);
592 // LStrings can be allocated on the heap if necessary.
593 // Then it can managed as part of an array of string pointers
595 LCleanedupHandle<RPointerArray<LString>, TResetAndDestroy> sarray;
597 for (TInt i = 0; i < n; ++i)
599 LString* s = new(ELeave) LString;
600 s->FormatL(_L("String %d"), i);
604 for (TInt i = 0, n = sarray->Count(); i < n; ++i)
607 tmp.FormatL(_L("String %d"), i);
608 test(tmp == *(*sarray)[i]);
609 test.Printf(_L("String %d = %S\n"), i, (*sarray)[i]);
615 // Any allocation failure in new(ELeave)LString throws
616 // KErrNoMemory and cleans up after itself fully
619 //coverity[resource_leak]
620 //As mentioned in the comment above any allocation failure is taken care of
621 TRAPD(status, new(ELeave) LString(100 * 1024 * 1024));
622 test(status == KErrNoMemory);
627 // Native C arrays (both heap and stack allocated) of LStrings
628 // also work, although their use is not recommended
631 LCleanedupArray<LString> sarray(new(ELeave) LString[n]);
633 for (TInt i = 0; i < n; ++i)
635 sarray[i].FormatL(_L("String %d"), i);
638 for (TInt i = 0; i < n; ++i)
641 tmp.FormatL(_L("String %d"), i);
642 test(tmp == sarray[i]);
643 test.Printf(_L("String %d = %S\n"), i, &sarray[i]);
648 // 8-bit wide null terminated character string support
650 // A default constructed LString8 starts empty, doesn't
651 // allocate any memory on the heap, and therefore the
652 // following cannot leave
655 // But it will grow on demand if you assign to it, so it has
656 // enough space to hold the copied string data, and so
657 // assignment may leave
660 // Similarly if you append to it with the leaving variant of
661 // Append, AppendL, if may grow on demand
664 // The += operator for LString8 also maps to AppendL
668 // An LString8 can be printed the same way as any descriptor
669 test.Printf(_L("Value: %S \n"), &s);
671 // An LString8 can be compared the same way as any descriptor
672 test(s == "One Two Three Testing ");
674 // An LString8 supports all TDesC and TDes methods
675 // LString findToken("Two ");
676 test(s.Find("Two ") == 4);
678 // LString8 matchPattern("*Two* ");
679 test(s.Match("*Two*") == 4);
680 test(s.Match("*T?o*") == 4);
682 // LString8 compare("some string");
683 test(s.Compare("One Two Three Testing ") == 0);
684 test(s.Compare("One Two Three Testing! ") < 0);
685 test(s.Compare("One Two Testing ") > 0);
687 // also LString8 ==,!=,>,<,<=,>=(L"some string");
688 test(s == "One Two Three Testing ");
689 test(s < "One Two Three Testing! ");
690 test(s > "One Two Testing ");
691 test(s != "not equal");
693 // Copies data into this 8-bit string descriptor, replacing any existing
694 // data, and expanding its heap buffer to accommodate if necessary.
695 // leaves on not being able to accomodate the new content
696 // both AssignL and += use CopyL internally
697 s.CopyL("new way of dealing with strings");
700 // Copy, Append,Insert,Replace,Justify the same way as TDesC8 and TDes8
702 // Copies data into this 8-bit string descriptor, replacing any existing
703 // data, and expanding its heap buffer to accommodate if necessary.
704 // leaves on not being able to accomodate the new content
705 // both AssignL and += use CopyL internally
706 s.CopyL("new way of dealing with strings");
707 s.CopyUCL("new way of dealing with strings");
708 test(s == "NEW WAY OF DEALING WITH STRINGS");
710 // Insert data into this descriptor.
711 // The length of this descriptor is changed to reflect the extra data.
712 // This leaving variant of the standard, non-leaving descriptor method
713 // differs in that this operation may cause the string descriptor's heap
714 // buffer to be reallocated in order to accommodate the new data. As a
715 // result, MaxLength() and Ptr() may return different values afterwards,
716 // and any existing raw pointers to into the descriptor data may be
718 s.CopyL("Some Content Can Be Into This String");
719 s.InsertL(20,"Inserted ");
720 test(s == "Some Content Can Be Inserted Into This String");
722 // Replace data in this descriptor.
723 // The specified length can be different to the length of the replacement data.
724 // The length of this descriptor changes to reflect the change of data.
725 // This leaving variant of the standard, non-leaving descriptor method
726 // differs in that this operation may cause the string descriptor's heap
727 // buffer to be reallocated in order to accommodate the new data. As a
728 // result, MaxLength() and Ptr() may return different values afterwards,
729 // and any existing raw pointers to into the descriptor data may be
731 s.CopyL("Some Content Can Be Decalper");
732 s.ReplaceL(20,8,"Replaced");
733 test(s == "Some Content Can Be Replaced");
735 // Append data onto the end of this descriptor's data.
736 // The length of this descriptor is incremented to reflect the new content.
737 // This leaving variant of the standard, non-leaving descriptor method
738 // differs in that this operation may cause the string descriptor's heap
739 // buffer to be reallocated in order to accommodate the new data. As a
740 // result, MaxLength() and Ptr() may return different values afterwards,
741 // and any existing raw pointers to into the descriptor data may be
743 s.CopyL("Try appending ");
744 s.AppendL("Try appending some more",3);
745 test(s == "Try appending Try");
747 // Copy data into this descriptor and justifies it, replacing any existing data.
748 // The length of this descriptor is set to reflect the new data.
749 // The target area is considered to be an area of specified width positioned at
750 // the beginning of this descriptor's data area. Source data is copied into, and
751 // aligned within this target area according to the specified alignment
753 // If the length of the target area is larger than the length of the source, then
754 // spare space within the target area is padded with the fill character.
755 // This leaving variant of the standard, non-leaving descriptor method
756 // differs in that this operation may cause the string descriptor's heap
757 // buffer to be reallocated in order to accommodate the new data. As a
758 // result, MaxLength() and Ptr() may return different values afterwards,
759 // and any existing raw pointers to into the descriptor data may be
761 s.CopyL("Justified");
762 s.JustifyL("Just",9,ERight,'x');
763 test(s == "xxxxxJust");
765 // Append data onto the end of this descriptor's data and justifies it.
766 // The source of the appended data is a memory location.
767 // The target area is considered to be an area of specified width, immediately
768 // following this descriptor's existing data. Source data is copied into, and
769 // aligned within, this target area according to the specified alignment instruction.
770 // If the length of the target area is larger than the length of the source,
771 // then spare space within the target area is padded with the fill character.
772 // This leaving variant of the standard, non-leaving descriptor method
773 // differs in that this operation may cause the string descriptor's heap
774 // buffer to be reallocated in order to accommodate the new data. As a
775 // result, MaxLength() and Ptr() may return different values afterwards,
776 // and any existing raw pointers to into the descriptor data may be
779 s.AppendJustifyL("Two Three",3,7,ERight,'x');
780 test(s == "One xxxxTwo" );
786 // This class demonstrates the use of the embeddable management
787 // classes in a conventional Symbian two-phase construction
789 class CManagedUserTwoPhase : public CBase
792 static CManagedUserTwoPhase* NewL(CTicker* aTicker)
794 // We can use the resource management utility classes in
795 // two-phase if we want to
796 LCleanedupPtr<CManagedUserTwoPhase> self(new(ELeave) CManagedUserTwoPhase);
797 self->ConstructL(aTicker);
798 // Calling Unmanage() disables cleanup and yields the
799 // previously managed pointer so that it can be safely
801 return self.Unmanage();
804 ~CManagedUserTwoPhase()
806 // The iTicker manager will automatically delete the CTicker
807 // The iTimer manager will automatically Close() the RTimer
812 // If we dereference the management object we get a CTicker&
818 // If we dereference the management object we get an RTimer&
824 virtual void ConstructL(CTicker* aTicker)
826 // Take ownership and manage aTicker
829 // Note use of -> to indirect through the management wrapper
830 iTimer->CreateLocal() OR_LEAVE;
833 CManagedUserTwoPhase()
835 // Everything interesting happens in ConstructL in this
838 // Default initialization of the iName LString does not
839 // allocate a heap buffer, and so cannot leave. As long as
840 // initialization is deferred to ConstructL, LStrings can be
841 // used safely with two-phase construction.
845 // We have to use LManagedXxx for fields, not LCleanedupXxx
846 LManagedPtr<CTicker> iTicker;
847 LManagedHandle<RTimer> iTimer;
850 // This class demonstrates the use of embedded management classes in
851 // the single-phase construction pattern, where a leave-safe
852 // constructor fully initializes the object.
854 // Note that where a class's constructor forms part of its exported
855 // public or protected contract, switching from a non-leaving to a
856 // potentially leaving constructor would be a BC break. On the other
857 // hand, if instantiation is entirely encapsulated within factory
858 // functions like NewL, there is no such BC restriction.
860 class CManagedUserSinglePhase : public CBase
863 // This macro is necessary to ensure cleanup is correctly handled
864 // in the event that a constructor may leave beneath a call to
866 CONSTRUCTORS_MAY_LEAVE
868 static CManagedUserSinglePhase* NewL(CTicker* aTicker)
870 return new(ELeave) CManagedUserSinglePhase(aTicker);
873 ~CManagedUserSinglePhase()
875 // The iTicker manager destructor will automatically Zap() the CTicker
876 // The iTimer manager destructor will automatically Close() the RTimer
881 // If we dereference the management object we get a CTicker&
887 // If we dereference the management object we get an RTimer&
892 CManagedUserSinglePhase(CTicker* aTicker)
893 // Take ownership and manage aTicker. Note that initialization
894 // of the LManagedXxx classes does not actually leave, but
895 // initialization of the LCleanedupXxx classes can.
898 // If iTicker initialization is successful but the constructor
899 // then goes on to leave later, iTicker (like all fields fully
900 // constructed at the point of a leave in a constructor) will
901 // be destructed, and the manager will cleanup the CTicker
903 // Note use of -> to indirect through the management wrapper
904 iTimer->CreateLocal() OR_LEAVE;
906 // Likewise if we leave here, both iTicker and iTimer will
907 // undergo managed cleanup
912 // We have to use LManagedXxx for fields, not LCleanedupXxx
913 LManagedPtr<CTicker, TTickerZapStrategy> iTicker;
914 LManagedHandle<RTimer> iTimer;
917 //Class definition of trivial R-Class
922 RSimple(){iData = NULL;}
924 //Open function sets value
925 void OpenL(TInt aValue)
927 iData = new(ELeave) TInt(aValue);
930 //Cleanup function – frees resource
937 //Cleanup function – frees resource
944 //Cleanup function – frees resource
951 //static cleanup function – frees aRSimple resources
952 static void Cleanup(TAny* aRSimple)
954 static_cast<RSimple*>(aRSimple)->Close();
964 //This sets the default cleanup behaviour for the RSimple class to
965 //be RSimple::ReleaseData.
966 //If this Macro is not used then the default cleanup behaviour
967 //would be to call RSimple::Close().
968 DEFINE_CLEANUP_FUNCTION(RSimple, ReleaseData);
971 void WalkthroughManagedL()
974 // Trivially exercise the manager-using classes defined above
975 CTicker* ticker1 = new(ELeave) CTicker;
976 LCleanedupPtr<CManagedUserTwoPhase> one(CManagedUserTwoPhase::NewL(ticker1));
977 test(&one->Ticker() == ticker1);
978 one->Timer().Cancel(); // Just to check we can get at it
980 CTicker* ticker2 = new(ELeave) CTicker;
981 LCleanedupPtr<CManagedUserSinglePhase> two(CManagedUserSinglePhase::NewL(ticker2));
982 test(&two->Ticker() == ticker2);
983 two->Timer().Cancel(); // Just to check we can get at it
985 // Both instances are automatically deleted as we go out of scope
988 // Always use LCleanedupXxx for locals, not LManagedXxx
991 // Begin the scenes the LCleanedupXxx constructors push a
992 // cleanup item onto the cleanup stack and so may leave. If
993 // there is a leave during construction, the supplied pointer
994 // will still get cleaned up.
995 LCleanedupPtr<CTicker> t(new(ELeave) CTicker);
997 // We can access CTicker's members via the management object
1001 test(t->iTicks == t->iTocks);
1003 // We can get at a reference to the managed object using *
1004 // when we need to, e.g. if we need to pass it to a function
1005 RegisterTicker(*t); // Takes a CTicker&
1007 // If some unfriendly interface needs a pointer rather than a
1008 // ref, we have a couple of options
1009 RegisterTickerPtr(&*t); // Takes a CTicker*
1010 RegisterTickerPtr(t.Get()); // Takes a CTicker*
1012 // Note the use of . in t.Get() above; this distinguishes
1013 // operations on the managing type from operations on the
1016 // When the management object goes out of scope, either
1017 // normally or as the result of a leave, the managed object is
1018 // automatically deleted
1022 // Sometimes you need to protect something temporarily before
1023 // transferring ownership e.g. by returning the pointer or
1024 // passing it to a function that takes ownership.
1026 LCleanedupPtr<CTicker> t(new(ELeave) CTicker);
1028 // Protected while we do this
1031 // But now we want to hand it off, so we use Unmanage() to
1032 // both return a pointer and break the management link
1033 TakeTickerOwnership(t.Unmanage());
1035 // Now when it goes out of scope, no cleanup action is
1040 // If needed, it is possible to reuse a manager by using = to
1041 // assign it a new managed object.
1043 // Not managing anything to start with
1044 LCleanedupPtr<CTicker> t;
1045 test(t.Get() == NULL);
1048 for (TInt i = 0; i < 10; ++i)
1050 // If an object is already being managed, it is cleaned up
1051 // before taking ownership of the new object
1052 t = new(ELeave) CTicker;
1054 // We're left owning the final ticker instance, all prior
1055 // instances having been automatically deleted
1059 // If you have stateful code where a pointer can sometimes be
1060 // NULL, as a convenience you can test the managing object
1061 // itself as a shortcut test for NULL
1062 LCleanedupPtr<CTicker> t(new(ELeave) CTicker);
1064 // Does t refer to NULL?
1070 t = NULL; // Also releases the currently managed CTicker
1072 // Does t refer to a non-NULL pointer?
1080 // LCleanedupPtr uses delete to cleanup by default, but
1081 // alternative cleanups can be specified
1083 // We just want to free this one and not invoke the destructor
1084 LCleanedupPtr<CTicker, TPointerFree> t(static_cast<CTicker*>(User::AllocL(sizeof(CTicker))));
1086 // Now User::Free() is called when t goes out of scope
1090 // As well as the stock options, custom cleanup policies can
1091 // also be defined. See above for the definition of
1093 LCleanedupPtr<CTicker, TTickerZapStrategy> t(new(ELeave) CTicker);
1095 // Now Zap() is called on the CTicker instance when t goes out of scope
1099 // LCleanedupHandle is very similar in behaviour to
1100 // LCleanedupPtr, the main difference being that it can define
1101 // and contain its own instance of a handle rather than
1102 // being supplied one
1103 LCleanedupHandle<RTimer> t;
1105 // Again, access to managed handle members is via ->
1106 t->CreateLocal() OR_LEAVE;
1109 // We can get a reference to the handle for passing to
1110 // functions using *
1113 // When the management object goes out of scope, either
1114 // normally or as the result of a leave, the managed object is
1115 // automatically cleanup by calling Close() on it
1119 // LCleanedupHandle calls Close() by default, but alternative
1120 // cleanups can be specified
1122 // We want this RPointerArray cleanup with with
1123 // ResetAndDestroy instead of Close()
1124 LCleanedupHandle<RPointerArray<HBufC>, TResetAndDestroy> array;
1125 for (TInt i = 0; i < 10; ++i)
1127 array->AppendL(HBufC::NewL(5));
1130 // Now when array goes out of scope, ResetAndDestroy is called
1135 // As well as the stock options, custom cleanup policies can
1136 // also be defined. See above for the definition of
1138 LCleanedupHandle<RTimer, TCancelClose> t;
1141 // Now Cancel() followed by Close() are called when t goes out
1147 // LCleanedupHandleRef calls Close() by default, but alternative
1148 // cleanups can be specified
1150 // We want this RPointerArray cleanup with with
1151 // ResetAndDestroy instead of Close()
1152 RPointerArray<HBufC> rar;
1153 // calls to functions that cannot leave here
1154 rar.Append(HBufC::NewL(5));
1155 rar.Append(HBufC::NewL(5));
1158 LCleanedupRef<RPointerArray<HBufC>, TResetAndDestroy> array(rar);
1159 // calls to functions that could leave here
1160 for (TInt i = 0; i < 10; ++i)
1162 array->AppendL(HBufC::NewL(5));
1165 // Now when array goes out of scope, ResetAndDestroy is called
1170 // Never mix direct cleanup stack API calls with management
1171 // class use within the same function, because their
1172 // interaction can be confusing and counter intuitive. Avoid
1173 // the use of LC methods that leave objects on the cleanup
1174 // stack, and use L methods instead.
1176 // If a badly-behaved API were to offer only an LC variant,
1177 // you would have to use it as follows
1178 HBufC* raw = HBufC::NewLC(5);
1179 // Must pop immediately to balance the cleanup stack, before
1180 // instantiating the manager
1181 CleanupStack::Pop();
1182 LCleanedupPtr<HBufC> wrapped(raw);
1185 //LCleanedupPtr<HBufC> buf(HBufC::NewLC(5));
1186 //CleanupStack::Pop();
1187 // because the manager will be popped (having been pushed
1188 // last), not the raw buf pointer as you might have hoped
1190 // A cleaner alternative may be to write your own L function
1191 // wrapper around the LC function supplied.
1193 // Luckily this situation (an LC method without a
1194 // corresponding L method) is rare in practice.
1198 // Although rarely used on Symbian OS, C++ arrays are
1199 // supported with a custom management class
1200 LCleanedupArray<CTicker> array(new CTicker[5]);
1202 // The array is cleaned up with delete[] on scope exit
1206 // Although most cases are best covered by applying custom
1207 // cleanup policies to the management classes already
1208 // described, there is also a general TCleanupItem style
1210 TAny* data = NULL; // But could be anything
1211 LCleanedupGuard guard1(BespokeCleanupFunction, data);
1212 // On scope exit BespokeCleanupFunction is called on data
1214 LCleanedupGuard guard2(BespokeCleanupFunction, data);
1215 // But cleanup can also be disabled in this case, as follows
1221 LCleanedupHandle<RFs> managedFs;
1222 r = managedFs->Connect();
1227 //default cleanup strategy is to call RFs::Close() on scope exit
1231 LCleanedupHandle<RSimple, TFree> simple;
1233 //Specified cleanup strategy is to call RSimple::Free() on scope exit
1236 //Because the DEFINE_CLEANUP_FUNCTION is defined above, the default
1237 //cleanup function for RSimple is RSimple::ReleaseData() rather than
1240 LCleanedupHandle<RSimple> simple;
1242 //Custom cleanup strategy is to call RSimple::ReleaseData() on scope exit
1248 //The RSimple class above defines a static cleanup function
1250 LCleanedupGuard guard(RSimple::Cleanup, &simple);
1254 //On scope exit RSimple::Cleanup() is called passing &simple
1258 void WalkthroughUsageL()
1262 test.Printf(_L("Size of RFile = %d"), sizeof(file));
1264 LCleanedupHandle<RFile> cFile;
1266 test.Printf(_L("Size of LCleanedupHandle<RFile> = %d"), sizeof(cFile));
1268 LCleanedupRef<RFile> crFile(file);
1270 test.Printf(_L("Size of LCleanedupRef<RFile> = %d"), sizeof(crFile));
1272 CTicker* tracker = new(ELeave) CTicker;
1273 //coverity[resource_leak]
1274 //As mentioned in the comment above any allocation failure is taken care of
1275 test.Printf(_L("Size of CTracker* = %d"), sizeof(tracker));
1277 LCleanedupPtr<CTicker> cTracker(tracker);
1279 test.Printf(_L("Size of LCleanedupHandle<RFile> = %d"), sizeof(LCleanedupPtr<CTicker>));
1284 WalkthroughStringsL();
1285 WalkthroughManagedL();
1286 WalkthroughUsageL();
1294 test.Start(_L("EUserHl Walkthrough"));
1297 CTrapCleanup* trapHandler=CTrapCleanup::New();
1298 test(trapHandler!=NULL);
1302 TRAPD(status, TestL());
1306 if (status != KErrNone) test.Printf(_L("Error: %d\n"), status);
1308 test.Printf(_L("Test Completed with Error: %d"),status);