os/ossrv/lowlevellibsandfws/genericusabilitylib/example/src/euserhl_walkthrough.cpp
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/ossrv/lowlevellibsandfws/genericusabilitylib/example/src/euserhl_walkthrough.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,1314 @@
1.4 +// Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +//
1.18 +
1.19 +#include <e32std.h>
1.20 +#include <f32file.h>
1.21 +#include <e32test.h>
1.22 +#include <euserhl.h>
1.23 +
1.24 +
1.25 +
1.26 +// Note: Methods are defined inline within classes here simply to make
1.27 +// the code shorter, keep related code closer together, and hopefully
1.28 +// make things easier to follow.
1.29 +
1.30 +RTest test(_L("EuserHl Walkthrough"));
1.31 +
1.32 +// Some dummy methods and data used in the walkthroughs below
1.33 +_LIT(KFill, "XXX");
1.34 +_LIT(KPath, "c:\\a\\b\\c");
1.35 +_LIT(KOne, "One ");
1.36 +_LIT(KTwo, "Two ");
1.37 +_LIT(KTesting, "Testing ");
1.38 +
1.39 +void MaybeLeaveL()
1.40 + {
1.41 + // Some code that may leave
1.42 + }
1.43 +
1.44 +HBufC* AllocateNameL(const TDesC& aDes)
1.45 + {
1.46 + return aDes.AllocL();
1.47 + }
1.48 +
1.49 +void ReadToMax(TDes& aDes)
1.50 + {
1.51 + aDes.SetMax();
1.52 + aDes.Repeat(KFill);
1.53 + }
1.54 +
1.55 +void GetCurrentPath(TDes& aDes)
1.56 + {
1.57 + aDes = KPath;
1.58 + }
1.59 +
1.60 +void GetCurrentPathStringL(LString& aString)
1.61 + {
1.62 + aString = L"c:\\a\\b\\c"; // Will auto-grow if necessary, may leave
1.63 + }
1.64 +
1.65 +LString AppendCurrentPathStringL(LString aString)
1.66 + {
1.67 + return aString+= L"c:\\a\\b\\c";
1.68 + }
1.69 +
1.70 +class CTicker : public CBase
1.71 + {
1.72 +public:
1.73 + void Tick() { ++iTicks; }
1.74 + void Tock() { ++iTocks; }
1.75 +
1.76 + void Zap() { delete this; }
1.77 +
1.78 +public:
1.79 + TInt iTicks;
1.80 + TInt iTocks;
1.81 + };
1.82 +
1.83 +// Defines a custom pointer cleanup policy that calls the Zap member
1.84 +class TTickerZapStrategy
1.85 + {
1.86 +public:
1.87 + static void Cleanup(CTicker* aPtr)
1.88 + {
1.89 + // The general template/class scaffolding remains the same
1.90 + // for all custom cleanups, just this cleanup body varies
1.91 + aPtr->Zap();
1.92 + test.Printf(_L("Zapped CTicker\n"));
1.93 + }
1.94 + };
1.95 +
1.96 +void RegisterTicker(CTicker& aTicker)
1.97 + {
1.98 + (void)aTicker;
1.99 + }
1.100 +
1.101 +void RegisterTickerPtr(CTicker* aTicker)
1.102 + {
1.103 + (void)aTicker;
1.104 + }
1.105 +
1.106 +void TakeTickerOwnership(CTicker* aTicker)
1.107 + {
1.108 + delete aTicker;
1.109 + }
1.110 +
1.111 +void RegisterTimer(RTimer& aTimer)
1.112 + {
1.113 + (void)aTimer;
1.114 + }
1.115 +
1.116 +// Defines a custom handle cleanup policy that calls Cancel then Close
1.117 +class TCancelClose
1.118 + {
1.119 +public:
1.120 + template <class T>
1.121 + static void Cleanup(T* aHandle)
1.122 + {
1.123 + // The general template/class scaffolding remains the same
1.124 + // for all custom cleanups, just this cleanup body varies
1.125 + aHandle->Cancel();
1.126 + aHandle->Close();
1.127 + test.Printf(_L("Cancel Closed RTimer\n"));
1.128 + }
1.129 + };
1.130 +
1.131 +void BespokeCleanupFunction(TAny* aData)
1.132 + {
1.133 + (void)aData;
1.134 + test.Printf(_L("BespokeCleanupFunction\n"));
1.135 + }
1.136 +
1.137 +// The walkthroughs themselves
1.138 +
1.139 +// This class demonstrates the use of an embedded LString in the
1.140 +// conventional Symbian two-phase construction pattern. We've chosen
1.141 +// to implement the temporary leave protection in NewL in terms of
1.142 +// LCleanedupPtr instead of the the CleanupStack API in this example.
1.143 +class CStringUserTwoPhase : public CBase
1.144 + {
1.145 +public:
1.146 + static CStringUserTwoPhase* NewL(const TDesC& aName)
1.147 + {
1.148 + // We can use the resource management utility classes in
1.149 + // two-phase if we want to
1.150 + LCleanedupPtr<CStringUserTwoPhase> self(new(ELeave) CStringUserTwoPhase);
1.151 + self->ConstructL(aName);
1.152 + // Calling Unmanage() disables cleanup and yields the
1.153 + // previously managed pointer so that it can be safely
1.154 + // returned
1.155 + return self.Unmanage();
1.156 + }
1.157 +
1.158 + virtual void ConstructL(const TDesC& aName)
1.159 + {
1.160 + // This assignment may leave if LString fails to allocate a
1.161 + // heap buffer large enough to hold the data in aName
1.162 + iName = aName;
1.163 + }
1.164 +
1.165 + ~CStringUserTwoPhase()
1.166 + {
1.167 + // The iName LString cleans up after itself automatically
1.168 + }
1.169 +
1.170 + const TDesC& Name()
1.171 + {
1.172 + // We can just return an LString directly as a const TDesC
1.173 + return iName;
1.174 + }
1.175 +
1.176 +protected:
1.177 + CStringUserTwoPhase()
1.178 + {
1.179 + // Everything interesting happens in ConstructL in this
1.180 + // version.
1.181 +
1.182 + // Default initialization of the iName LString does not
1.183 + // allocate a heap buffer, and so cannot leave. As long as
1.184 + // initialization is deferred to ConstructL, LStrings can be
1.185 + // used safely with two-phase construction.
1.186 + }
1.187 +
1.188 +protected:
1.189 + LString iName;
1.190 + };
1.191 +
1.192 +// This class demonstrates the use of an embedded LString in the
1.193 +// single-phase construction pattern, where a leave-safe constructor
1.194 +// fully initializes the object.
1.195 +//
1.196 +// Note that where a class's constructor forms part of its exported
1.197 +// public or protected contract, switching from a non-leaving to a
1.198 +// potentially leaving constructor would be a BC break. On the other
1.199 +// hand, if instantiation is entirely encapsulated within factory
1.200 +// functions like NewL, there is no such BC restriction.
1.201 +class CStringUserSinglePhase : public CBase
1.202 + {
1.203 +public:
1.204 + // This macro is necessary to ensure cleanup is correctly handled
1.205 + // in the event that a constructor may leave beneath a call to
1.206 + // new(ELeave)
1.207 + CONSTRUCTORS_MAY_LEAVE
1.208 +
1.209 + static CStringUserSinglePhase* NewL(const TDesC& aName)
1.210 + {
1.211 + return new(ELeave) CStringUserSinglePhase(aName);
1.212 + }
1.213 +
1.214 + ~CStringUserSinglePhase()
1.215 + {
1.216 + // The iName LString cleans up after itself automatically
1.217 + }
1.218 +
1.219 + const TDesC& Name()
1.220 + {
1.221 + // We can just return an LString directly as a const TDesC
1.222 + return iName;
1.223 + }
1.224 +
1.225 +protected:
1.226 + CStringUserSinglePhase(const TDesC& aName)
1.227 + // This initialization of iName may leave because LString
1.228 + // needs to allocate a heap buffer to copy the aName string
1.229 + // data into
1.230 + : iName(aName)
1.231 + {
1.232 + // If iName initialization is successful but the constructor
1.233 + // then goes on to leave later, iName (like all fields fully
1.234 + // constructed at the point of a leave in a constructor) will
1.235 + // be destructed, and so clean up after itself
1.236 + MaybeLeaveL();
1.237 + }
1.238 +
1.239 +protected:
1.240 + LString iName;
1.241 + };
1.242 +
1.243 +
1.244 +void WalkthroughStringsL()
1.245 + {
1.246 +
1.247 + {
1.248 + // Trivially exercise the LString using classes defined above
1.249 +
1.250 + LCleanedupPtr<CStringUserTwoPhase> one(CStringUserTwoPhase::NewL(KOne));
1.251 + test.Printf(_L("Single phase name: %S\n"), &one->Name());
1.252 +
1.253 + LCleanedupPtr<CStringUserSinglePhase> two(CStringUserSinglePhase::NewL(KTwo));
1.254 + test.Printf(_L("Two phase name: %S\n"), &two->Name());
1.255 +
1.256 + // Both instances are automatically deleted as we go out of scope
1.257 + }
1.258 +
1.259 + {
1.260 + // A default constructed LString starts empty, doesn't
1.261 + // allocate any memory on the heap, and therefore the
1.262 + // following cannot leave
1.263 + LString s;
1.264 +
1.265 + // But it will grow on demand if you assign to it, so it has
1.266 + // enough space to hold the copied string data, and so
1.267 + // assignment may leave
1.268 + s = L"One ";
1.269 +
1.270 + // Similarly if you append to it with the leaving variant of
1.271 + // Append, AppendL, if may grow on demand
1.272 + s.AppendL(L"Two ");
1.273 +
1.274 + // The += operator for LString also maps to AppendL
1.275 + s += L"Three ";
1.276 +
1.277 + // You can also use new leaving format methods that also grow
1.278 + // on demand
1.279 + s.AppendFormatL(KTesting);
1.280 +
1.281 + // This general style of use of LString may be preferable to
1.282 + // typical descriptor use for a number of reasons e.g. it
1.283 + // avoids the common temptation to set an artificial maximum
1.284 + // buffer size; it avoids massive conservative over-allocation
1.285 + // when the average case length of a string is far less than
1.286 + // the worst-case maximum; it will not surprise you (compared
1.287 + // to the alternative of a large stack-allocated TBuf) by
1.288 + // triggering stack overflow.
1.289 +
1.290 + // An LString can be printed the same way as any descriptor
1.291 + test.Printf(_L("Value: %S\n"), &s);
1.292 +
1.293 + // An LString supports all TDesC and TDes methods
1.294 + // LString findToken(L"Two ");
1.295 + test(s.Find(L"Two ") == 4);
1.296 +
1.297 + // LString matchPattern(L"*Two* ");
1.298 + test(s.Match(L"*Two*") == 4);
1.299 + test(s.Match(L"*T?o*") == 4);
1.300 +
1.301 + // LString compare(L"some string");
1.302 + test(s.Compare(L"One Two Three Testing ") == 0);
1.303 + test(s.Compare(L"One Two Three Testing! ") < 0);
1.304 + test(s.Compare(L"One Two Testing ") > 0);
1.305 +
1.306 + // also LString ==,!=,>,<,<=,>=(L"some string");
1.307 + test(s == L"One Two Three Testing ");
1.308 + test(s < L"One Two Three Testing! ");
1.309 + test(s > L"One Two Testing ");
1.310 + test(s != L"not equal");
1.311 +
1.312 + // An LString supports all TDesC and TDes operators
1.313 + test(s[4] == TChar('T'));
1.314 +
1.315 + TInt untrimmed = s.Length();
1.316 + s.Trim();
1.317 + test(s.Length() == untrimmed - 1);
1.318 +
1.319 + s.UpperCase();
1.320 + test.Printf(_L("UpperCase: %S\n"), &s);
1.321 + s.LowerCase();
1.322 + test.Printf(_L("LowerCase: %S\n"), &s);
1.323 +
1.324 + // The underlying heap allocated buffer is released
1.325 + // automatically when the LString goes out of scope, either
1.326 + // normally or through a leave
1.327 + }
1.328 + {
1.329 + // Copy, Append,Insert,Replace,Justify the same way as TDesC and TDes
1.330 +
1.331 + LString s;
1.332 + // Copies data into this 8-bit string descriptor, replacing any existing
1.333 + // data, and expanding its heap buffer to accommodate if necessary.
1.334 + // leaves on not being able to accomodate the new content
1.335 + // both AssignL and += use CopyL internally
1.336 + s.CopyL(L"new way of dealing with strings");
1.337 + s.CopyUCL(L"new way of dealing with strings");
1.338 + test(s == L"NEW WAY OF DEALING WITH STRINGS");
1.339 +
1.340 + // Insert data into this descriptor.
1.341 + // The length of this descriptor is changed to reflect the extra data.
1.342 + // This leaving variant of the standard, non-leaving descriptor method
1.343 + // differs in that this operation may cause the string descriptor's heap
1.344 + // buffer to be reallocated in order to accommodate the new data. As a
1.345 + // result, MaxLength() and Ptr() may return different values afterwards,
1.346 + // and any existing raw pointers to into the descriptor data may be
1.347 + // invalidated.
1.348 + s.CopyL(L"Some Content Can Be Into This String");
1.349 + s.InsertL(20,L"Inserted ");
1.350 + test(s == L"Some Content Can Be Inserted Into This String");
1.351 +
1.352 + // Replace data in this descriptor.
1.353 + // The specified length can be different to the length of the replacement data.
1.354 + // The length of this descriptor changes to reflect the change of data.
1.355 + // This leaving variant of the standard, non-leaving descriptor method
1.356 + // differs in that this operation may cause the string descriptor's heap
1.357 + // buffer to be reallocated in order to accommodate the new data. As a
1.358 + // result, MaxLength() and Ptr() may return different values afterwards,
1.359 + // and any existing raw pointers to into the descriptor data may be
1.360 + // invalidated.
1.361 + s.CopyL(L"Some Content Can Be Decalper");
1.362 + s.ReplaceL(20,8,L"Replaced");
1.363 + test(s == L"Some Content Can Be Replaced");
1.364 +
1.365 + // Append data onto the end of this descriptor's data.
1.366 + // The length of this descriptor is incremented to reflect the new content.
1.367 + // This leaving variant of the standard, non-leaving descriptor method
1.368 + // differs in that this operation may cause the string descriptor's heap
1.369 + // buffer to be reallocated in order to accommodate the new data. As a
1.370 + // result, MaxLength() and Ptr() may return different values afterwards,
1.371 + // and any existing raw pointers to into the descriptor data may be
1.372 + // invalidated.
1.373 + s.CopyL(L"Try appending ");
1.374 + s.AppendL(L"Try appending some more",3);
1.375 + test(s == L"Try appending Try");
1.376 +
1.377 + // Copy data into this descriptor and justifies it, replacing any existing data.
1.378 + // The length of this descriptor is set to reflect the new data.
1.379 + // The target area is considered to be an area of specified width positioned at
1.380 + // the beginning of this descriptor's data area. Source data is copied into, and
1.381 + // aligned within this target area according to the specified alignment
1.382 + // instruction.
1.383 + // If the length of the target area is larger than the length of the source, then
1.384 + // spare space within the target area is padded with the fill character.
1.385 + // This leaving variant of the standard, non-leaving descriptor method
1.386 + // differs in that this operation may cause the string descriptor's heap
1.387 + // buffer to be reallocated in order to accommodate the new data. As a
1.388 + // result, MaxLength() and Ptr() may return different values afterwards,
1.389 + // and any existing raw pointers to into the descriptor data may be
1.390 + // invalidated.
1.391 + s.CopyL(L"Justified");
1.392 + s.JustifyL(L"Just",9,ERight,'x');
1.393 + test(s == L"xxxxxJust");
1.394 +
1.395 + // Append data onto the end of this descriptor's data and justifies it.
1.396 + // The source of the appended data is a memory location.
1.397 + // The target area is considered to be an area of specified width, immediately
1.398 + // following this descriptor's existing data. Source data is copied into, and
1.399 + // aligned within, this target area according to the specified alignment instruction.
1.400 + // If the length of the target area is larger than the length of the source,
1.401 + // then spare space within the target area is padded with the fill character.
1.402 + // This leaving variant of the standard, non-leaving descriptor method
1.403 + // differs in that this operation may cause the string descriptor's heap
1.404 + // buffer to be reallocated in order to accommodate the new data. As a
1.405 + // result, MaxLength() and Ptr() may return different values afterwards,
1.406 + // and any existing raw pointers to into the descriptor data may be
1.407 + // invalidated.
1.408 + s.CopyL(L"One ");
1.409 + s.AppendJustifyL(L"Two Three",3,7,ERight,'x');
1.410 + test(s == L"One xxxxTwo" );
1.411 +
1.412 + }
1.413 + {
1.414 + // You can initialize with a MaxLength value
1.415 + LString s(KMaxFileName); // This operation may leave
1.416 + test(s.MaxLength() == KMaxFileName);
1.417 +
1.418 + // And you can dynamically adjust MaxLength later using
1.419 + // SetMaxLengthL if you want an exact allocated size
1.420 + // Setting MaxLength on construction or via SetMaxLengthL is
1.421 + // exact; calling MaxLength() immediately afterwards is
1.422 + // guaranteed to return exactly the value you specified
1.423 + s.SetMaxLengthL(2 * KMaxFileName);
1.424 + test(s.MaxLength() == 2 * KMaxFileName);
1.425 +
1.426 + // Pre-setting MaxLength is important when passing an LString
1.427 + // as a TDes to a library function, because the LString can't
1.428 + // be auto-grown via the TDes API
1.429 +
1.430 + }
1.431 +
1.432 + {
1.433 + // You can initialize from any descriptor/literal/[wide]character string and the
1.434 + // string data is copied into the LString
1.435 + LString s(L"One "); // From a character string
1.436 + s += L"Two ";
1.437 + LString half(s.Left(s.Length() / 2)); // Left returns a TPtrC
1.438 + test.Printf(_L("All: %S, Half: %S\n"), &s, &half);
1.439 +
1.440 + // On the other hand, you can initialize from a returned
1.441 + // HBufC* and the LString automatically takes ownership
1.442 + LString own(AllocateNameL(KTesting));
1.443 + test.Printf(_L("What I own: %S\n"), &own);
1.444 +
1.445 + // Following that you can re-assign an HBufC to an existing
1.446 + // string using the assignment operator
1.447 + // taking ownership of the new content.
1.448 + own = AllocateNameL(KTesting);
1.449 +
1.450 + // Following that you can re-assign an HBufC to an existing
1.451 + // string. The string destroys its original content before
1.452 + // taking ownership of the new content.
1.453 + own.Assign(AllocateNameL(KTesting));
1.454 +
1.455 + // The content of one string can similarly be assigned
1.456 + // to another to avoid copying. In this example, the content
1.457 + // is detached from 's' and transfered to 'own'.
1.458 + own.Assign(s);
1.459 +
1.460 + // The same content transfer can be achieved from an RBuf to a
1.461 + // string. You may need to do this if a legacy method returns
1.462 + // you an RBuf. The RBuf is emptied of its content.
1.463 + RBuf16 buf;
1.464 + buf.CreateL(KOne);
1.465 + own.Assign(buf);
1.466 +
1.467 + // You can also assign a simple text array to a string as its
1.468 + // new buffer. This method initialises the length to zero.
1.469 + own.Assign((TText*)User::Alloc(24*(TInt)sizeof(TText)), 24);
1.470 +
1.471 + // If the buffer has already been filled with some characters
1.472 + // then you supply the length in this alternative Assign method.
1.473 + own.Assign((TText*)User::Alloc(24*(TInt)sizeof(TText)), 12,24);
1.474 +
1.475 + // Each Assign destroys the old content before assuming ownership
1.476 + // of the new.
1.477 + // As usual the last content of the string is destroyed when the
1.478 + // LString goes out of scope
1.479 + }
1.480 +
1.481 + {
1.482 + // You can reserve extra free space in preparation for an
1.483 + // operation that adds characters to the string. You may
1.484 + // need to do this when you cannot use any of the auto-buffer
1.485 + // extending LString methods to achieve your objective.
1.486 + LString s(L"One ");
1.487 + s.ReserveFreeCapacityL(4);
1.488 + test(s.Length() == 4);
1.489 + test(s.MaxLength() >= 8);
1.490 +
1.491 + // Almost all the methods that may extended the string buffer,
1.492 + // including the explicit ReserveFreeCapacityL, but excluding
1.493 + // SetMaxLengthL, attempt to grow the size exponentially.
1.494 + // The Exponential growth pattern is expected to give better
1.495 + // performance at an amortised complexity of O(n) when adding n characters.
1.496 + // If the exponential growth is less than the supplied extra size
1.497 + // then the supplied size is used instead to save time.
1.498 + // The exponential growth is used in anticipation of further additions
1.499 + // to a string. This trades-off speed efficiency for space efficiency.
1.500 + // If required you may be able to swap the oversized buffer for
1.501 + // a more compact one using:
1.502 + s.Compress();
1.503 + test(s.MaxLength() >= 4); //note indefinite test
1.504 +
1.505 + // Resize attempts to re-allocate a smaller buffer to copy
1.506 + // the content into. If the new memory cannot be allocated then the
1.507 + // original string is left unaffected.
1.508 +
1.509 + // When you have finished using the content of a string you can
1.510 + // get its buffer released without destroying the string itself.
1.511 + // You may want to do this when using member declared strings.
1.512 + // Automatic strings are destroyed when they go out of scope.
1.513 + s.Reset();
1.514 + test(s.Length() == 0);
1.515 + test(s.MaxLength() == 0);
1.516 +
1.517 + }
1.518 +
1.519 + {
1.520 + // An LString can be passed directly to any function requiring
1.521 + // a const TDesC&
1.522 + TInt year = 2009;
1.523 +
1.524 + LString s;
1.525 + s.FormatL(_L("Happy New Year %d"), year);
1.526 + // InfoPrint takes a const TDesC&
1.527 + User::InfoPrint(s);
1.528 +
1.529 + LString pattern;
1.530 + pattern.FormatL(_L("*Year %d"), year);
1.531 + // Match takes a const TDesC& as a pattern
1.532 + TInt loc = s.Match(pattern);
1.533 + test(loc == 10);
1.534 + }
1.535 +
1.536 + {
1.537 + // An LString can be passed directly to any function requiring
1.538 + // a TDes& but care must always be taken to pre-set MaxLength
1.539 + // since LStrings can't be automatically grown via the TDes
1.540 + // interface
1.541 +
1.542 + LString s;
1.543 + // Calling GetCurrentPath(s) now would panic because LStrings
1.544 + // are initialized by default to MaxLength 0. Although s is
1.545 + // an LString GetCurrentPath takes a TDes& and so inside the function
1.546 + // s behaves as a TDes and would panic with USER 11 if the resulting
1.547 + // new length of s is greater than its maximum length.
1.548 + test(s.MaxLength() == 0);
1.549 +
1.550 + // Calling SetMaxLengthL will automatically realloc the
1.551 + // underlying buffer if required, and is guaranteed to leave
1.552 + // MaxLength() equal to the specified value
1.553 + s.SetMaxLengthL(KMaxFileName);
1.554 + GetCurrentPath(s);
1.555 + //LString pathString(L"c:\\a\\b\\c");
1.556 + test.Printf(_L("Path: %S\n"), &s);
1.557 + test(s == L"c:\\a\\b\\c");
1.558 +
1.559 + // If SetMaxLengthL adjusts MaxLength lower than the current
1.560 + // Length, the data is truncated to the new MaxLength and
1.561 + // Length set to the new MaxLength
1.562 + s.SetMaxLengthL(s.Length() / 2);
1.563 + test.Printf(_L("Truncated path: %S\n"), &s);
1.564 + test(s.Length() == s.MaxLength());
1.565 +
1.566 + // An initial MaxLength can be specified when constructing an
1.567 + // LString. Note that unlike the default constructor, this
1.568 + // variant allocates and may leave.
1.569 + LString s2(KMaxFileName);
1.570 + GetCurrentPath(s2);
1.571 + test.Printf(_L("Path: %S\n"), &s2);
1.572 + test(s2 == L"c:\\a\\b\\c");
1.573 +
1.574 + // Your code and APIs can benefit from LString's auto-growth
1.575 + // behaviour by accepting an LString to fill in as an output
1.576 + // parameter. Using LString rather than TDes parameters means
1.577 + // that the function is able to safely increase the size of the
1.578 + // string as the LString will re-allocate as necessary
1.579 + LString s3;
1.580 + // GetCurrentPathStringL takes an LString&
1.581 + GetCurrentPathStringL(s3);
1.582 + test.Printf(_L("Path: %S\n"), &s3);
1.583 + test(s3 == L"c:\\a\\b\\c");
1.584 +
1.585 + // As a well-defined value class, if you want to, LStrings can
1.586 + // be passed and returned by value. This is relatively
1.587 + // inefficient however due to the amount of copying and heap
1.588 + // reallocation involved.
1.589 + LString s4(AppendCurrentPathStringL(s3));
1.590 + test.Printf(_L("Appended path: %S\n"), &s4);
1.591 + test(s4.Length() == s3.Length() * 2);
1.592 + }
1.593 +
1.594 + {
1.595 + // LStrings can be allocated on the heap if necessary.
1.596 + // Then it can managed as part of an array of string pointers
1.597 + TInt n = 5;
1.598 + LCleanedupHandle<RPointerArray<LString>, TResetAndDestroy> sarray;
1.599 +
1.600 + for (TInt i = 0; i < n; ++i)
1.601 + {
1.602 + LString* s = new(ELeave) LString;
1.603 + s->FormatL(_L("String %d"), i);
1.604 + sarray->Append(s);
1.605 + }
1.606 +
1.607 + for (TInt i = 0, n = sarray->Count(); i < n; ++i)
1.608 + {
1.609 + LString tmp;
1.610 + tmp.FormatL(_L("String %d"), i);
1.611 + test(tmp == *(*sarray)[i]);
1.612 + test.Printf(_L("String %d = %S\n"), i, (*sarray)[i]);
1.613 + }
1.614 +
1.615 + }
1.616 +
1.617 + {
1.618 + // Any allocation failure in new(ELeave)LString throws
1.619 + // KErrNoMemory and cleans up after itself fully
1.620 +
1.621 + __UHEAP_MARK;
1.622 + //coverity[resource_leak]
1.623 + //As mentioned in the comment above any allocation failure is taken care of
1.624 + TRAPD(status, new(ELeave) LString(100 * 1024 * 1024));
1.625 + test(status == KErrNoMemory);
1.626 + __UHEAP_MARKEND;
1.627 + }
1.628 +
1.629 + {
1.630 + // Native C arrays (both heap and stack allocated) of LStrings
1.631 + // also work, although their use is not recommended
1.632 +
1.633 + TInt n = 5;
1.634 + LCleanedupArray<LString> sarray(new(ELeave) LString[n]);
1.635 +
1.636 + for (TInt i = 0; i < n; ++i)
1.637 + {
1.638 + sarray[i].FormatL(_L("String %d"), i);
1.639 + }
1.640 +
1.641 + for (TInt i = 0; i < n; ++i)
1.642 + {
1.643 + LString tmp;
1.644 + tmp.FormatL(_L("String %d"), i);
1.645 + test(tmp == sarray[i]);
1.646 + test.Printf(_L("String %d = %S\n"), i, &sarray[i]);
1.647 + }
1.648 +
1.649 + }
1.650 + {
1.651 + // 8-bit wide null terminated character string support
1.652 +
1.653 + // A default constructed LString8 starts empty, doesn't
1.654 + // allocate any memory on the heap, and therefore the
1.655 + // following cannot leave
1.656 + LString8 s;
1.657 +
1.658 + // But it will grow on demand if you assign to it, so it has
1.659 + // enough space to hold the copied string data, and so
1.660 + // assignment may leave
1.661 + s ="One ";
1.662 +
1.663 + // Similarly if you append to it with the leaving variant of
1.664 + // Append, AppendL, if may grow on demand
1.665 + s.AppendL("Two ");
1.666 +
1.667 + // The += operator for LString8 also maps to AppendL
1.668 + s +="Three ";
1.669 + s +="Testing ";
1.670 +
1.671 + // An LString8 can be printed the same way as any descriptor
1.672 + test.Printf(_L("Value: %S \n"), &s);
1.673 +
1.674 + // An LString8 can be compared the same way as any descriptor
1.675 + test(s == "One Two Three Testing ");
1.676 +
1.677 + // An LString8 supports all TDesC and TDes methods
1.678 + // LString findToken("Two ");
1.679 + test(s.Find("Two ") == 4);
1.680 +
1.681 + // LString8 matchPattern("*Two* ");
1.682 + test(s.Match("*Two*") == 4);
1.683 + test(s.Match("*T?o*") == 4);
1.684 +
1.685 + // LString8 compare("some string");
1.686 + test(s.Compare("One Two Three Testing ") == 0);
1.687 + test(s.Compare("One Two Three Testing! ") < 0);
1.688 + test(s.Compare("One Two Testing ") > 0);
1.689 +
1.690 + // also LString8 ==,!=,>,<,<=,>=(L"some string");
1.691 + test(s == "One Two Three Testing ");
1.692 + test(s < "One Two Three Testing! ");
1.693 + test(s > "One Two Testing ");
1.694 + test(s != "not equal");
1.695 +
1.696 + // Copies data into this 8-bit string descriptor, replacing any existing
1.697 + // data, and expanding its heap buffer to accommodate if necessary.
1.698 + // leaves on not being able to accomodate the new content
1.699 + // both AssignL and += use CopyL internally
1.700 + s.CopyL("new way of dealing with strings");
1.701 +
1.702 +
1.703 + // Copy, Append,Insert,Replace,Justify the same way as TDesC8 and TDes8
1.704 +
1.705 + // Copies data into this 8-bit string descriptor, replacing any existing
1.706 + // data, and expanding its heap buffer to accommodate if necessary.
1.707 + // leaves on not being able to accomodate the new content
1.708 + // both AssignL and += use CopyL internally
1.709 + s.CopyL("new way of dealing with strings");
1.710 + s.CopyUCL("new way of dealing with strings");
1.711 + test(s == "NEW WAY OF DEALING WITH STRINGS");
1.712 +
1.713 + // Insert data into this descriptor.
1.714 + // The length of this descriptor is changed to reflect the extra data.
1.715 + // This leaving variant of the standard, non-leaving descriptor method
1.716 + // differs in that this operation may cause the string descriptor's heap
1.717 + // buffer to be reallocated in order to accommodate the new data. As a
1.718 + // result, MaxLength() and Ptr() may return different values afterwards,
1.719 + // and any existing raw pointers to into the descriptor data may be
1.720 + // invalidated.
1.721 + s.CopyL("Some Content Can Be Into This String");
1.722 + s.InsertL(20,"Inserted ");
1.723 + test(s == "Some Content Can Be Inserted Into This String");
1.724 +
1.725 + // Replace data in this descriptor.
1.726 + // The specified length can be different to the length of the replacement data.
1.727 + // The length of this descriptor changes to reflect the change of data.
1.728 + // This leaving variant of the standard, non-leaving descriptor method
1.729 + // differs in that this operation may cause the string descriptor's heap
1.730 + // buffer to be reallocated in order to accommodate the new data. As a
1.731 + // result, MaxLength() and Ptr() may return different values afterwards,
1.732 + // and any existing raw pointers to into the descriptor data may be
1.733 + // invalidated.
1.734 + s.CopyL("Some Content Can Be Decalper");
1.735 + s.ReplaceL(20,8,"Replaced");
1.736 + test(s == "Some Content Can Be Replaced");
1.737 +
1.738 + // Append data onto the end of this descriptor's data.
1.739 + // The length of this descriptor is incremented to reflect the new content.
1.740 + // This leaving variant of the standard, non-leaving descriptor method
1.741 + // differs in that this operation may cause the string descriptor's heap
1.742 + // buffer to be reallocated in order to accommodate the new data. As a
1.743 + // result, MaxLength() and Ptr() may return different values afterwards,
1.744 + // and any existing raw pointers to into the descriptor data may be
1.745 + // invalidated.
1.746 + s.CopyL("Try appending ");
1.747 + s.AppendL("Try appending some more",3);
1.748 + test(s == "Try appending Try");
1.749 +
1.750 + // Copy data into this descriptor and justifies it, replacing any existing data.
1.751 + // The length of this descriptor is set to reflect the new data.
1.752 + // The target area is considered to be an area of specified width positioned at
1.753 + // the beginning of this descriptor's data area. Source data is copied into, and
1.754 + // aligned within this target area according to the specified alignment
1.755 + // instruction.
1.756 + // If the length of the target area is larger than the length of the source, then
1.757 + // spare space within the target area is padded with the fill character.
1.758 + // This leaving variant of the standard, non-leaving descriptor method
1.759 + // differs in that this operation may cause the string descriptor's heap
1.760 + // buffer to be reallocated in order to accommodate the new data. As a
1.761 + // result, MaxLength() and Ptr() may return different values afterwards,
1.762 + // and any existing raw pointers to into the descriptor data may be
1.763 + // invalidated.
1.764 + s.CopyL("Justified");
1.765 + s.JustifyL("Just",9,ERight,'x');
1.766 + test(s == "xxxxxJust");
1.767 +
1.768 + // Append data onto the end of this descriptor's data and justifies it.
1.769 + // The source of the appended data is a memory location.
1.770 + // The target area is considered to be an area of specified width, immediately
1.771 + // following this descriptor's existing data. Source data is copied into, and
1.772 + // aligned within, this target area according to the specified alignment instruction.
1.773 + // If the length of the target area is larger than the length of the source,
1.774 + // then spare space within the target area is padded with the fill character.
1.775 + // This leaving variant of the standard, non-leaving descriptor method
1.776 + // differs in that this operation may cause the string descriptor's heap
1.777 + // buffer to be reallocated in order to accommodate the new data. As a
1.778 + // result, MaxLength() and Ptr() may return different values afterwards,
1.779 + // and any existing raw pointers to into the descriptor data may be
1.780 + // invalidated.
1.781 + s.CopyL("One ");
1.782 + s.AppendJustifyL("Two Three",3,7,ERight,'x');
1.783 + test(s == "One xxxxTwo" );
1.784 +
1.785 + }
1.786 +
1.787 + }
1.788 +
1.789 +// This class demonstrates the use of the embeddable management
1.790 +// classes in a conventional Symbian two-phase construction
1.791 +// pattern.
1.792 +class CManagedUserTwoPhase : public CBase
1.793 + {
1.794 +public:
1.795 + static CManagedUserTwoPhase* NewL(CTicker* aTicker)
1.796 + {
1.797 + // We can use the resource management utility classes in
1.798 + // two-phase if we want to
1.799 + LCleanedupPtr<CManagedUserTwoPhase> self(new(ELeave) CManagedUserTwoPhase);
1.800 + self->ConstructL(aTicker);
1.801 + // Calling Unmanage() disables cleanup and yields the
1.802 + // previously managed pointer so that it can be safely
1.803 + // returned
1.804 + return self.Unmanage();
1.805 + }
1.806 +
1.807 + ~CManagedUserTwoPhase()
1.808 + {
1.809 + // The iTicker manager will automatically delete the CTicker
1.810 + // The iTimer manager will automatically Close() the RTimer
1.811 + }
1.812 +
1.813 + CTicker& Ticker()
1.814 + {
1.815 + // If we dereference the management object we get a CTicker&
1.816 + return *iTicker;
1.817 + }
1.818 +
1.819 + RTimer& Timer()
1.820 + {
1.821 + // If we dereference the management object we get an RTimer&
1.822 + return *iTimer;
1.823 + }
1.824 +
1.825 +private:
1.826 +
1.827 + virtual void ConstructL(CTicker* aTicker)
1.828 + {
1.829 + // Take ownership and manage aTicker
1.830 + iTicker = aTicker;
1.831 +
1.832 + // Note use of -> to indirect through the management wrapper
1.833 + iTimer->CreateLocal() OR_LEAVE;
1.834 + }
1.835 +
1.836 + CManagedUserTwoPhase()
1.837 + {
1.838 + // Everything interesting happens in ConstructL in this
1.839 + // version.
1.840 +
1.841 + // Default initialization of the iName LString does not
1.842 + // allocate a heap buffer, and so cannot leave. As long as
1.843 + // initialization is deferred to ConstructL, LStrings can be
1.844 + // used safely with two-phase construction.
1.845 + }
1.846 +
1.847 +private:
1.848 + // We have to use LManagedXxx for fields, not LCleanedupXxx
1.849 + LManagedPtr<CTicker> iTicker;
1.850 + LManagedHandle<RTimer> iTimer;
1.851 + };
1.852 +
1.853 +// This class demonstrates the use of embedded management classes in
1.854 +// the single-phase construction pattern, where a leave-safe
1.855 +// constructor fully initializes the object.
1.856 +//
1.857 +// Note that where a class's constructor forms part of its exported
1.858 +// public or protected contract, switching from a non-leaving to a
1.859 +// potentially leaving constructor would be a BC break. On the other
1.860 +// hand, if instantiation is entirely encapsulated within factory
1.861 +// functions like NewL, there is no such BC restriction.
1.862 +
1.863 +class CManagedUserSinglePhase : public CBase
1.864 + {
1.865 +public:
1.866 + // This macro is necessary to ensure cleanup is correctly handled
1.867 + // in the event that a constructor may leave beneath a call to
1.868 + // new(ELeave)
1.869 + CONSTRUCTORS_MAY_LEAVE
1.870 +
1.871 + static CManagedUserSinglePhase* NewL(CTicker* aTicker)
1.872 + {
1.873 + return new(ELeave) CManagedUserSinglePhase(aTicker);
1.874 + }
1.875 +
1.876 + ~CManagedUserSinglePhase()
1.877 + {
1.878 + // The iTicker manager destructor will automatically Zap() the CTicker
1.879 + // The iTimer manager destructor will automatically Close() the RTimer
1.880 + }
1.881 +
1.882 + CTicker& Ticker()
1.883 + {
1.884 + // If we dereference the management object we get a CTicker&
1.885 + return *iTicker;
1.886 + }
1.887 +
1.888 + RTimer& Timer()
1.889 + {
1.890 + // If we dereference the management object we get an RTimer&
1.891 + return *iTimer;
1.892 + }
1.893 +
1.894 +private:
1.895 + CManagedUserSinglePhase(CTicker* aTicker)
1.896 + // Take ownership and manage aTicker. Note that initialization
1.897 + // of the LManagedXxx classes does not actually leave, but
1.898 + // initialization of the LCleanedupXxx classes can.
1.899 + : iTicker(aTicker)
1.900 + {
1.901 + // If iTicker initialization is successful but the constructor
1.902 + // then goes on to leave later, iTicker (like all fields fully
1.903 + // constructed at the point of a leave in a constructor) will
1.904 + // be destructed, and the manager will cleanup the CTicker
1.905 +
1.906 + // Note use of -> to indirect through the management wrapper
1.907 + iTimer->CreateLocal() OR_LEAVE;
1.908 +
1.909 + // Likewise if we leave here, both iTicker and iTimer will
1.910 + // undergo managed cleanup
1.911 + MaybeLeaveL();
1.912 + }
1.913 +
1.914 +private:
1.915 + // We have to use LManagedXxx for fields, not LCleanedupXxx
1.916 + LManagedPtr<CTicker, TTickerZapStrategy> iTicker;
1.917 + LManagedHandle<RTimer> iTimer;
1.918 + };
1.919 +
1.920 +//Class definition of trivial R-Class
1.921 +class RSimple
1.922 + {
1.923 +public:
1.924 +
1.925 + RSimple(){iData = NULL;}
1.926 +
1.927 + //Open function sets value
1.928 + void OpenL(TInt aValue)
1.929 + {
1.930 + iData = new(ELeave) TInt(aValue);
1.931 + }
1.932 +
1.933 + //Cleanup function – frees resource
1.934 + void Close()
1.935 + {
1.936 + delete iData;
1.937 + iData = NULL;
1.938 + }
1.939 +
1.940 + //Cleanup function – frees resource
1.941 + void Free()
1.942 + {
1.943 + delete iData;
1.944 + iData = NULL;
1.945 + }
1.946 +
1.947 + //Cleanup function – frees resource
1.948 + void ReleaseData()
1.949 + {
1.950 + delete iData;
1.951 + iData = NULL;
1.952 + }
1.953 +
1.954 + //static cleanup function – frees aRSimple resources
1.955 + static void Cleanup(TAny* aRSimple)
1.956 + {
1.957 + static_cast<RSimple*>(aRSimple)->Close();
1.958 + }
1.959 +
1.960 +
1.961 +private:
1.962 + TInt* iData;
1.963 +
1.964 + };
1.965 +
1.966 +
1.967 +//This sets the default cleanup behaviour for the RSimple class to
1.968 +//be RSimple::ReleaseData.
1.969 +//If this Macro is not used then the default cleanup behaviour
1.970 +//would be to call RSimple::Close().
1.971 +DEFINE_CLEANUP_FUNCTION(RSimple, ReleaseData);
1.972 +
1.973 +
1.974 +void WalkthroughManagedL()
1.975 + {
1.976 + {
1.977 + // Trivially exercise the manager-using classes defined above
1.978 + CTicker* ticker1 = new(ELeave) CTicker;
1.979 + LCleanedupPtr<CManagedUserTwoPhase> one(CManagedUserTwoPhase::NewL(ticker1));
1.980 + test(&one->Ticker() == ticker1);
1.981 + one->Timer().Cancel(); // Just to check we can get at it
1.982 +
1.983 + CTicker* ticker2 = new(ELeave) CTicker;
1.984 + LCleanedupPtr<CManagedUserSinglePhase> two(CManagedUserSinglePhase::NewL(ticker2));
1.985 + test(&two->Ticker() == ticker2);
1.986 + two->Timer().Cancel(); // Just to check we can get at it
1.987 +
1.988 + // Both instances are automatically deleted as we go out of scope
1.989 + }
1.990 +
1.991 + // Always use LCleanedupXxx for locals, not LManagedXxx
1.992 +
1.993 + {
1.994 + // Begin the scenes the LCleanedupXxx constructors push a
1.995 + // cleanup item onto the cleanup stack and so may leave. If
1.996 + // there is a leave during construction, the supplied pointer
1.997 + // will still get cleaned up.
1.998 + LCleanedupPtr<CTicker> t(new(ELeave) CTicker);
1.999 +
1.1000 + // We can access CTicker's members via the management object
1.1001 + // using ->
1.1002 + t->Tick();
1.1003 + t->Tock();
1.1004 + test(t->iTicks == t->iTocks);
1.1005 +
1.1006 + // We can get at a reference to the managed object using *
1.1007 + // when we need to, e.g. if we need to pass it to a function
1.1008 + RegisterTicker(*t); // Takes a CTicker&
1.1009 +
1.1010 + // If some unfriendly interface needs a pointer rather than a
1.1011 + // ref, we have a couple of options
1.1012 + RegisterTickerPtr(&*t); // Takes a CTicker*
1.1013 + RegisterTickerPtr(t.Get()); // Takes a CTicker*
1.1014 +
1.1015 + // Note the use of . in t.Get() above; this distinguishes
1.1016 + // operations on the managing type from operations on the
1.1017 + // managed object
1.1018 +
1.1019 + // When the management object goes out of scope, either
1.1020 + // normally or as the result of a leave, the managed object is
1.1021 + // automatically deleted
1.1022 + }
1.1023 +
1.1024 + {
1.1025 + // Sometimes you need to protect something temporarily before
1.1026 + // transferring ownership e.g. by returning the pointer or
1.1027 + // passing it to a function that takes ownership.
1.1028 +
1.1029 + LCleanedupPtr<CTicker> t(new(ELeave) CTicker);
1.1030 +
1.1031 + // Protected while we do this
1.1032 + MaybeLeaveL();
1.1033 +
1.1034 + // But now we want to hand it off, so we use Unmanage() to
1.1035 + // both return a pointer and break the management link
1.1036 + TakeTickerOwnership(t.Unmanage());
1.1037 +
1.1038 + // Now when it goes out of scope, no cleanup action is
1.1039 + // performed
1.1040 + }
1.1041 +
1.1042 + {
1.1043 + // If needed, it is possible to reuse a manager by using = to
1.1044 + // assign it a new managed object.
1.1045 +
1.1046 + // Not managing anything to start with
1.1047 + LCleanedupPtr<CTicker> t;
1.1048 + test(t.Get() == NULL);
1.1049 + test(&*t == NULL);
1.1050 +
1.1051 + for (TInt i = 0; i < 10; ++i)
1.1052 + {
1.1053 + // If an object is already being managed, it is cleaned up
1.1054 + // before taking ownership of the new object
1.1055 + t = new(ELeave) CTicker;
1.1056 + }
1.1057 + // We're left owning the final ticker instance, all prior
1.1058 + // instances having been automatically deleted
1.1059 + }
1.1060 +
1.1061 + {
1.1062 + // If you have stateful code where a pointer can sometimes be
1.1063 + // NULL, as a convenience you can test the managing object
1.1064 + // itself as a shortcut test for NULL
1.1065 + LCleanedupPtr<CTicker> t(new(ELeave) CTicker);
1.1066 +
1.1067 + // Does t refer to NULL?
1.1068 + if (!t)
1.1069 + {
1.1070 + test(EFalse);
1.1071 + }
1.1072 +
1.1073 + t = NULL; // Also releases the currently managed CTicker
1.1074 +
1.1075 + // Does t refer to a non-NULL pointer?
1.1076 + if (t)
1.1077 + {
1.1078 + test(EFalse);
1.1079 + }
1.1080 + }
1.1081 +
1.1082 + {
1.1083 + // LCleanedupPtr uses delete to cleanup by default, but
1.1084 + // alternative cleanups can be specified
1.1085 +
1.1086 + // We just want to free this one and not invoke the destructor
1.1087 + LCleanedupPtr<CTicker, TPointerFree> t(static_cast<CTicker*>(User::AllocL(sizeof(CTicker))));
1.1088 +
1.1089 + // Now User::Free() is called when t goes out of scope
1.1090 + }
1.1091 +
1.1092 + {
1.1093 + // As well as the stock options, custom cleanup policies can
1.1094 + // also be defined. See above for the definition of
1.1095 + // TTickerZap.
1.1096 + LCleanedupPtr<CTicker, TTickerZapStrategy> t(new(ELeave) CTicker);
1.1097 +
1.1098 + // Now Zap() is called on the CTicker instance when t goes out of scope
1.1099 + }
1.1100 +
1.1101 + {
1.1102 + // LCleanedupHandle is very similar in behaviour to
1.1103 + // LCleanedupPtr, the main difference being that it can define
1.1104 + // and contain its own instance of a handle rather than
1.1105 + // being supplied one
1.1106 + LCleanedupHandle<RTimer> t;
1.1107 +
1.1108 + // Again, access to managed handle members is via ->
1.1109 + t->CreateLocal() OR_LEAVE;
1.1110 + t->Cancel();
1.1111 +
1.1112 + // We can get a reference to the handle for passing to
1.1113 + // functions using *
1.1114 + RegisterTimer(*t);
1.1115 +
1.1116 + // When the management object goes out of scope, either
1.1117 + // normally or as the result of a leave, the managed object is
1.1118 + // automatically cleanup by calling Close() on it
1.1119 + }
1.1120 +
1.1121 + {
1.1122 + // LCleanedupHandle calls Close() by default, but alternative
1.1123 + // cleanups can be specified
1.1124 +
1.1125 + // We want this RPointerArray cleanup with with
1.1126 + // ResetAndDestroy instead of Close()
1.1127 + LCleanedupHandle<RPointerArray<HBufC>, TResetAndDestroy> array;
1.1128 + for (TInt i = 0; i < 10; ++i)
1.1129 + {
1.1130 + array->AppendL(HBufC::NewL(5));
1.1131 + }
1.1132 +
1.1133 + // Now when array goes out of scope, ResetAndDestroy is called
1.1134 + // to clean it up
1.1135 + }
1.1136 +
1.1137 + {
1.1138 + // As well as the stock options, custom cleanup policies can
1.1139 + // also be defined. See above for the definition of
1.1140 + // TCancelClose.
1.1141 + LCleanedupHandle<RTimer, TCancelClose> t;
1.1142 + t->CreateLocal();
1.1143 +
1.1144 + // Now Cancel() followed by Close() are called when t goes out
1.1145 + // of scope
1.1146 + }
1.1147 +
1.1148 +
1.1149 + {
1.1150 + // LCleanedupHandleRef calls Close() by default, but alternative
1.1151 + // cleanups can be specified
1.1152 +
1.1153 + // We want this RPointerArray cleanup with with
1.1154 + // ResetAndDestroy instead of Close()
1.1155 + RPointerArray<HBufC> rar;
1.1156 + // calls to functions that cannot leave here
1.1157 + rar.Append(HBufC::NewL(5));
1.1158 + rar.Append(HBufC::NewL(5));
1.1159 +
1.1160 +
1.1161 + LCleanedupRef<RPointerArray<HBufC>, TResetAndDestroy> array(rar);
1.1162 + // calls to functions that could leave here
1.1163 + for (TInt i = 0; i < 10; ++i)
1.1164 + {
1.1165 + array->AppendL(HBufC::NewL(5));
1.1166 + }
1.1167 +
1.1168 + // Now when array goes out of scope, ResetAndDestroy is called
1.1169 + // to clean it up
1.1170 + }
1.1171 +
1.1172 + {
1.1173 + // Never mix direct cleanup stack API calls with management
1.1174 + // class use within the same function, because their
1.1175 + // interaction can be confusing and counter intuitive. Avoid
1.1176 + // the use of LC methods that leave objects on the cleanup
1.1177 + // stack, and use L methods instead.
1.1178 +
1.1179 + // If a badly-behaved API were to offer only an LC variant,
1.1180 + // you would have to use it as follows
1.1181 + HBufC* raw = HBufC::NewLC(5);
1.1182 + // Must pop immediately to balance the cleanup stack, before
1.1183 + // instantiating the manager
1.1184 + CleanupStack::Pop();
1.1185 + LCleanedupPtr<HBufC> wrapped(raw);
1.1186 +
1.1187 + // Never do this:
1.1188 + //LCleanedupPtr<HBufC> buf(HBufC::NewLC(5));
1.1189 + //CleanupStack::Pop();
1.1190 + // because the manager will be popped (having been pushed
1.1191 + // last), not the raw buf pointer as you might have hoped
1.1192 +
1.1193 + // A cleaner alternative may be to write your own L function
1.1194 + // wrapper around the LC function supplied.
1.1195 +
1.1196 + // Luckily this situation (an LC method without a
1.1197 + // corresponding L method) is rare in practice.
1.1198 + }
1.1199 +
1.1200 + {
1.1201 + // Although rarely used on Symbian OS, C++ arrays are
1.1202 + // supported with a custom management class
1.1203 + LCleanedupArray<CTicker> array(new CTicker[5]);
1.1204 +
1.1205 + // The array is cleaned up with delete[] on scope exit
1.1206 + }
1.1207 +
1.1208 + {
1.1209 + // Although most cases are best covered by applying custom
1.1210 + // cleanup policies to the management classes already
1.1211 + // described, there is also a general TCleanupItem style
1.1212 + // cleanup option
1.1213 + TAny* data = NULL; // But could be anything
1.1214 + LCleanedupGuard guard1(BespokeCleanupFunction, data);
1.1215 + // On scope exit BespokeCleanupFunction is called on data
1.1216 +
1.1217 + LCleanedupGuard guard2(BespokeCleanupFunction, data);
1.1218 + // But cleanup can also be disabled in this case, as follows
1.1219 + guard2.Dismiss();
1.1220 + }
1.1221 +
1.1222 + {
1.1223 + TInt r =KErrNone;
1.1224 + LCleanedupHandle<RFs> managedFs;
1.1225 + r = managedFs->Connect();
1.1226 + if (r != KErrNone)
1.1227 + {
1.1228 + User::Leave(r);
1.1229 + }
1.1230 + //default cleanup strategy is to call RFs::Close() on scope exit
1.1231 + }
1.1232 +
1.1233 + {
1.1234 + LCleanedupHandle<RSimple, TFree> simple;
1.1235 + simple->OpenL(23);
1.1236 + //Specified cleanup strategy is to call RSimple::Free() on scope exit
1.1237 + }
1.1238 +
1.1239 + //Because the DEFINE_CLEANUP_FUNCTION is defined above, the default
1.1240 + //cleanup function for RSimple is RSimple::ReleaseData() rather than
1.1241 + //RSimple::Close()
1.1242 + {
1.1243 + LCleanedupHandle<RSimple> simple;
1.1244 + simple->OpenL(23);
1.1245 + //Custom cleanup strategy is to call RSimple::ReleaseData() on scope exit
1.1246 + }
1.1247 +
1.1248 + {
1.1249 + RSimple simple;
1.1250 +
1.1251 + //The RSimple class above defines a static cleanup function
1.1252 + //RSimple::Cleanup.
1.1253 + LCleanedupGuard guard(RSimple::Cleanup, &simple);
1.1254 +
1.1255 + simple.OpenL(10);
1.1256 +
1.1257 + //On scope exit RSimple::Cleanup() is called passing &simple
1.1258 + }
1.1259 + }
1.1260 +
1.1261 +void WalkthroughUsageL()
1.1262 + {
1.1263 + RFile file;
1.1264 +
1.1265 + test.Printf(_L("Size of RFile = %d"), sizeof(file));
1.1266 +
1.1267 + LCleanedupHandle<RFile> cFile;
1.1268 +
1.1269 + test.Printf(_L("Size of LCleanedupHandle<RFile> = %d"), sizeof(cFile));
1.1270 +
1.1271 + LCleanedupRef<RFile> crFile(file);
1.1272 +
1.1273 + test.Printf(_L("Size of LCleanedupRef<RFile> = %d"), sizeof(crFile));
1.1274 +
1.1275 + CTicker* tracker = new(ELeave) CTicker;
1.1276 + //coverity[resource_leak]
1.1277 + //As mentioned in the comment above any allocation failure is taken care of
1.1278 + test.Printf(_L("Size of CTracker* = %d"), sizeof(tracker));
1.1279 +
1.1280 + LCleanedupPtr<CTicker> cTracker(tracker);
1.1281 +
1.1282 + test.Printf(_L("Size of LCleanedupHandle<RFile> = %d"), sizeof(LCleanedupPtr<CTicker>));
1.1283 + }
1.1284 +
1.1285 +TInt TestL()
1.1286 + {
1.1287 + WalkthroughStringsL();
1.1288 + WalkthroughManagedL();
1.1289 + WalkthroughUsageL();
1.1290 +
1.1291 + return KErrNone;
1.1292 + }
1.1293 +
1.1294 +TInt E32Main()
1.1295 + {
1.1296 +
1.1297 + test.Start(_L("EUserHl Walkthrough"));
1.1298 + test.Title();
1.1299 +
1.1300 + CTrapCleanup* trapHandler=CTrapCleanup::New();
1.1301 + test(trapHandler!=NULL);
1.1302 +
1.1303 + __UHEAP_MARK;
1.1304 +
1.1305 + TRAPD(status, TestL());
1.1306 +
1.1307 + __UHEAP_MARKEND;
1.1308 +
1.1309 + if (status != KErrNone) test.Printf(_L("Error: %d\n"), status);
1.1310 +
1.1311 + test.Printf(_L("Test Completed with Error: %d"),status);
1.1312 +
1.1313 + return status;
1.1314 + }
1.1315 +
1.1316 +
1.1317 +// eof