lowlevellibsandfws/genericusabilitylib/documentation/dox/mainpage.dox
changeset 22 ddc455616bd6
parent 18 47c74d1534e1
child 24 8aa38fd255c2
child 44 97b0fb8a2cc2
equal deleted inserted replaced
18:47c74d1534e1 22:ddc455616bd6
     1 /**
       
     2 @mainpage 
       
     3 
       
     4 @par Overview 
       
     5 
       
     6 @par
       
     7 
       
     8 This document describes new core APIs for semi-automatic resource
       
     9 management designed to begin to increase the baseline usability of
       
    10 Symbian OS for developers. We would welcome feedback, improvement
       
    11 suggestions, and defect reports. Note that there is a Q&A section at
       
    12 the bottom of this page that explains some of the background rationale
       
    13 behind the design choices we have made to get to this point.
       
    14 
       
    15 Please send any questions or review feedback you have to: core.idioms@symbian.com
       
    16 
       
    17 The new APIs include the following:
       
    18 
       
    19 - A new type category: the L-class
       
    20   - Allows leaving constructors and can rely on automatic destructor execution for
       
    21     cleanup (explained in more detail below)
       
    22 - New general purpose, self-managing string classes that can be used much 
       
    23   like T-classes 
       
    24   - LString16 
       
    25     - For manipulating strings of 16 bit characters
       
    26     - Usually used via the ::LString typedef
       
    27   - LString8 
       
    28     - For manipulating strings of 8 bit characters
       
    29   - ::LData
       
    30     - Type alias for LString8 allowing the intent to use it as a raw (non-character) data buffer to be expressed
       
    31   - The LString classes are based on the descriptor APIs and are fully interoperable with descriptors
       
    32   - The LString classes can grow on demand and do not always need to be
       
    33     initialized with a fixed reserve maximum length
       
    34 - New "smart pointer" style utility classes for managing resources referenced from local variables, 
       
    35   which may be used instead of the existing cleanup stack API
       
    36   - LCleanedupPtr
       
    37     - Alternative to PushL(CBase*)/Pop()/PopAndDestroy() code sequences
       
    38   - LCleanedupHandle
       
    39     - Alternative to CleanupClosePushL()/Pop()/PopAndDestroy() code sequences
       
    40   - See also the more rarely used LCleanedupRef, LCleanedupArray, and LCleanedupGuard
       
    41 - New "smart pointer" style utility classes for managing resources referenced from data members, 
       
    42   which reduce the need for manually-written destructors 
       
    43   - LManagedPtr
       
    44     - Alternative to calling delete manually in a destructor for the managed data member
       
    45   - LManagedHandle
       
    46     - Alternative to calling Close() manually in a destructor for the managed data member
       
    47   - See also the more rarely used LManagedRef, LManagedArray, and LManagedGuard
       
    48 - Enablers for the (optional, typically private) use of single-phase construction
       
    49   - #CONSTRUCTORS_MAY_LEAVE 
       
    50     - A class declaration flagging that the class's constructors may leave
       
    51   - Normally used in combination with the LManagedXxx classes to ensure reliable cleanup in case of a constructor leaving
       
    52   - Normally hidden behind a conventional Symbian NewL() abstraction
       
    53 - New utilities for making correct, error checking code easier to read
       
    54   - New #OR_LEAVE postfix macro
       
    55     - Alternative to wrapping User::LeaveIfError() around an expression
       
    56 
       
    57 The motivation for the new APIs is to make it easier to write correct,
       
    58 less brittle code in the first instance, but perhaps more so to make
       
    59 the resulting code easier to read and easier to modify safely later.
       
    60 
       
    61 Some guiding principles:
       
    62 
       
    63 - Resource management should be handled either fully automatically or declaratively 
       
    64   at point of definition as far as possible
       
    65   - Helps to eliminate mismatches between code that pushes and code that pops
       
    66   - Helps to eliminate mismatches between code that constructs and code that destructs
       
    67   - Removes the need to duplicate cleanup code (or modify your code's structure) to correctly handle functions with multiple return points 
       
    68   - Makes changing code safer and easier by reducing dependencies between different areas of the code
       
    69 - It should be easier and lighter weight to write and maintain leave-safe code
       
    70   - So that more people are prepared to make the investment to do it right
       
    71 - The primary function of code should not be swamped by auxiliary error checking and resource management 
       
    72   - The key logic should be front and centre, and read as straightforwardly as possible
       
    73 - It should be easier to write fully general code
       
    74   - Unsafe and/or overly conservative maximum size limitations should not be 
       
    75     encouraged by making that style of code easier to write
       
    76 - Terminology should be as conventional as possible
       
    77   - We call a string a string
       
    78 
       
    79 To help illustrate the new APIs, here is a sampling of idiomatic code
       
    80 implemented first in terms of the current Symbian APIs, and alongside
       
    81 in terms of the new APIs.
       
    82 
       
    83 <table width="100%">
       
    84 
       
    85 <tr valign="top">
       
    86 <td>Current APIs</td><td>New APIs</td>
       
    87 </tr>
       
    88 
       
    89 <tr valign="top">
       
    90 <td>
       
    91 @code
       
    92 {
       
    93 TBuf<KMaxQuery> query; // fixed worst-case max
       
    94 query.Format(KQueryFormat, param);
       
    95 ExecuteQueryL(query);
       
    96 }
       
    97 @endcode
       
    98 </td>
       
    99 <td>
       
   100 @code
       
   101 {
       
   102 LString query; // can grow its heap buffer on demand
       
   103 query.FormatL(KQueryFormat, param);
       
   104 ExecuteQueryL(query);
       
   105 } // query buffer released on normal scope exit or leave
       
   106 @endcode
       
   107 </td>
       
   108 </tr>
       
   109 
       
   110 <tr valign="top">
       
   111 <td>
       
   112 @code
       
   113 {
       
   114 HBufC* queryc = HBufC::NewLC(KTooBigForStackMaxQuery);
       
   115 TPtr query(queryc->Des());
       
   116 BuildQueryL(query);
       
   117 ExecuteQueryL(query);
       
   118 CleanupStack::PopAndDestroy();
       
   119 }
       
   120 @endcode
       
   121 </td>
       
   122 <td>
       
   123 @code
       
   124 {
       
   125 LString query;
       
   126 BuildQueryL(query);
       
   127 ExecuteQueryL(query);
       
   128 }
       
   129 @endcode
       
   130 </td>
       
   131 </tr>
       
   132 
       
   133 <tr valign="top">
       
   134 <td>
       
   135 @code
       
   136 {
       
   137 RBuf query;
       
   138 query.CleanupClosePushL();
       
   139 query.CreateL(TooBigForStackMaxQuery);
       
   140 BuildQueryL(query);
       
   141 ExecuteQueryL(query);
       
   142 CleanupStack::PopAndDestroy();
       
   143 }
       
   144 @endcode
       
   145 </td>
       
   146 <td>
       
   147 @code
       
   148 {
       
   149 LString query;
       
   150 BuildQueryL(query);
       
   151 ExecuteQueryL(query);
       
   152 }
       
   153 @endcode
       
   154 </td>
       
   155 </tr>
       
   156 
       
   157 <tr valign="top">
       
   158 <td>
       
   159 
       
   160 @code
       
   161 {
       
   162 CQuery* query = CQuery::NewL();
       
   163 CleanupStack::PushL(query);
       
   164 query->BuildQueryL();
       
   165 query->ExecuteQueryL();
       
   166 CleanupStack::PopAndDestroy();
       
   167 }
       
   168 @endcode
       
   169 
       
   170 </td>
       
   171 <td>
       
   172 
       
   173 @code
       
   174 {
       
   175 LCleanedupPtr<CQuery> query(CQuery::NewL()); 
       
   176 query->BuildQueryL();
       
   177 query->ExecuteQueryL();
       
   178 } // query deleted on normal scope exit or leave
       
   179 @endcode
       
   180 
       
   181 </td>
       
   182 </tr>
       
   183 
       
   184 <tr valign="top">
       
   185 <td>
       
   186 
       
   187 @code
       
   188 {
       
   189 CQuery* query = CQuery::NewL();
       
   190 CleanupStack::PushL(query);
       
   191 query->BuildQueryL();
       
   192 CleanupStack::Pop();
       
   193 return query;
       
   194 }
       
   195 @endcode
       
   196 
       
   197 </td>
       
   198 <td>
       
   199 
       
   200 @code
       
   201 {
       
   202 LCleanedupPtr<CQuery> query(CQuery::NewL()); 
       
   203 query->BuildQueryL();
       
   204 return query.Unmanage(); 
       
   205 // query was protected until Unmanage() was called
       
   206 }
       
   207 @endcode
       
   208 
       
   209 </td>
       
   210 </tr>
       
   211 
       
   212 <tr valign="top">
       
   213 <td>
       
   214 
       
   215 @code
       
   216 {
       
   217 RQuery query;
       
   218 CleanupClosePushL(query);
       
   219 query.BuildQueryL();
       
   220 query.ExecuteQueryL();
       
   221 CleanupStack::PopAndDestroy();
       
   222 }
       
   223 @endcode
       
   224 
       
   225 </td>
       
   226 <td>
       
   227 
       
   228 @code
       
   229 {
       
   230 LCleanedupHandle<RQuery> query;
       
   231 query->BuildQueryL();
       
   232 query->ExecuteQueryL();
       
   233 } // query is closed on normal scope exit or leave
       
   234 @endcode
       
   235 
       
   236 </td>
       
   237 </tr>
       
   238 
       
   239 </table>
       
   240 
       
   241 @par Concepts
       
   242 
       
   243 These APIs introduce a new category of Symbian type: the
       
   244 L-class. L-classes have characteristics close to standard C++ value
       
   245 and handle classes, including the following:
       
   246 
       
   247 - Constructors, operators, and implicit operations may leave
       
   248 - They are self-managing and do not require auxiliary memory management logic
       
   249 
       
   250 L-classes may be used like T-classes except that they can own
       
   251 resources, they typically rely on guaranteed execution of their
       
   252 destructors, and they cannot necessarily be naively bitwise
       
   253 copied. Any code that manipulates L-class instances must be
       
   254 leave-safe. The only exception to this rule is if the particular
       
   255 operations being used are explicitly documented not to leave (e.g. the
       
   256 default LString constructor and all the LManagedXXX constructors).
       
   257 
       
   258 The L prefix denotes that these classes may be Liberal when it comes
       
   259 to Leaving, while being Leave-safe themselves. 
       
   260 
       
   261 The implementation of many L classes relies on the leave=throw mapping
       
   262 current in Symbian OS since v9.1 because this guarantees destructor
       
   263 execution for objects allocated on the stack.
       
   264 
       
   265 @par Notes on Usage
       
   266 
       
   267 For ease of experimentation during review, all the new APIs are
       
   268 packaged for use as a statically-linked bundle:
       
   269 
       
   270 - #include <euserhl.h> in your code
       
   271 - STATICLIBRARY euserhl.lib in your mmp
       
   272 
       
   273 Some important dos and don'ts (most of which leavescan will reliably flag):
       
   274 
       
   275 - The LCleanedupXXX classes are for managing locals only, and may not be used to manage data members. This is because the LCleanedupXXX classes are implemented in terms of the legacy cleanup stack.
       
   276 - The LCleanedupXXX classes must not be used in the same function as the legacy cleanup stack APIs. They can interact unintuitively and this is best avoided. It is all or nothing at function granularity.
       
   277 - Use L-suffix method variants with LCleanedupXXX, never LC-suffix variants that manipulate the cleanup stack. This is for the same reason as the previous point. 
       
   278 - The LManagedXXX classes should only be used for data members. If they are used for locals, they can interact unintuitively with cleanup stack based cleanup (from other functions on the call stack) with respect to cleanup ordering.
       
   279 - Whenever you write code that manipulates LString or other L-prefix classes, always conservatively leave-safe your code. This is now easier with the LCleanedupXXX utilities.
       
   280 
       
   281 On the resource management utility classes:
       
   282 
       
   283 - A managed object's member functions may be called directly on the managing container, but -> notation must be used to access them
       
   284 - Implicit coercions from managing containers to managed types are not defined; instead the dereference operator * must be used e.g. to obtain a reference suitable for passing as a parameter to another function 
       
   285 - Pop()-like semantics (as opposed to PopAndDestroy()) is achieved by calling Unmanage() on the managing container before it goes out of scope; Unmanage() returns the managed object which can then be returned from your function, or passed to a different function which takes over ownership. Unlike Pop(), however, Unmanage() simply sets a flag to disable cleanup and may be called at any time without worrying about stack discipline
       
   286 - It is still typically necessary to declare, define, and export a destructor, even if its implementation (currently) contains no hand-written code
       
   287   - The destructor must be available wherever delete may be called on an instance of the class
       
   288   - The compiler will automatically generate destruction logic behind the scenes for LString and LManagedXxx data members, even if you don't write any code yourself
       
   289   - The destructor may of course change over time anyway
       
   290 
       
   291 On the LString classes:
       
   292 
       
   293 - Existing library functions that accept a modifiable TDes cannot take advantage of LString's on-demand growth behaviour; the necessary capacity must first be explicitly reserved in the LString before calling such functions (this can be done either with a constructor parameter or by calling SetMaxLengthL())
       
   294 - Any descriptor method that could panic due to lack of capacity is replaced with a leaving variant that grows the heap e.g. instead of Append(), LString defines AppendL(). The non-leaving TDes versions are hidden to avoid accidental use, although they can still be accessed via a TDes typed (as opposed to LString typed) ref or pointer
       
   295 - Programmers new to Symbian OS could first be introduced to descriptors and string handling via just const TDesC& (for input parameter contracts), TDes (for output parameter contracts), and LString for implementation. LStrings can be initialized by value from any descriptor return type, and by automatically taking ownership in the HBufC* return case.
       
   296 
       
   297 On single-phase construction:
       
   298 
       
   299 - This option is enabled by LString and the LManagedXxx classes
       
   300   - However you implement construction behind the scenes, NewL is an important abstraction
       
   301   - Think hard before using single-phase construction in a framework class designed for derivation in client code
       
   302 - LString and the LManagedXxx classes may be used safely in conventional Symbian two-phase construction as well as standard C++ style single-phase construction
       
   303   - LManagedXxx construction never leaves, and is safe to perform at any stage
       
   304   - Default construction of an empty LString never leaves, but other initializations must be deferred to ConstructL
       
   305 - An understanding of standard C++ construction semantics is required before attempting to use single-phase construction
       
   306   - If a constructor throws mid-way through, its matching destructor is not invoked to clean up
       
   307   - Instead all data members fully-constructed to the point of the leave are automatically destructed
       
   308   - Therefore, in effect, all class cleanup must typically be achieved via data member destruction
       
   309   - The presence of a non-empty destructor is a warning sign if you are using single-phase construction
       
   310 
       
   311 An annotated example using the new APIs follows (the
       
   312 euserhl_walkthrough example goes into much more detail than we do
       
   313 here).
       
   314 
       
   315 @code
       
   316 #include <e32std.h>
       
   317 #include <f32file.h>
       
   318 #include <euserhl.h> // Includes all the new APIs
       
   319 
       
   320 class CFinder : public CBase
       
   321 	{
       
   322 public:
       
   323 	// We have opted to use single-phase construction here, and some of 
       
   324 	// our constructor's initialization actions may leave. In order to 
       
   325 	// guarantee full cleanup in all cases, we have to declare this fact.
       
   326 	CONSTRUCTORS_MAY_LEAVE
       
   327 	static CFinder* NewL(const TDesC& aPattern);
       
   328 	~CFinder();
       
   329 	void GetNextMatchL(TDes& aMatch);
       
   330 
       
   331 protected:
       
   332 	CFinder(const TDesC& aPattern);
       
   333 
       
   334 protected:
       
   335 	LString iPattern;
       
   336 	LManagedHandle<RFs> iFs; // We always use LManagedXxx for data members
       
   337 	// ...
       
   338 	};
       
   339 
       
   340 CFinder* CFinder::NewL(const TDesC& aPattern)
       
   341 	{
       
   342 	return new(ELeave) CFinder(aPattern);
       
   343 	}
       
   344 
       
   345 CFinder::CFinder(const TDesC& aPattern) 
       
   346 	// This initializer may leave, since the LString will allocate a
       
   347 	// heap buffer large enough to contain a copy of aPattern's data
       
   348 	: iPattern(aPattern) 
       
   349 	{
       
   350 	// If connection fails and we leave here, iPattern's destructor
       
   351 	// will be called automatically, and the string's resources will
       
   352 	// be released
       
   353 	iFs->Connect() OR_LEAVE;
       
   354 	}
       
   355 
       
   356 CFinder::~CFinder()
       
   357 	{
       
   358 	// Automatic destruction of each of the data members does all of the
       
   359 	// work for us: iPattern's heap buffer if freed, while Close() is
       
   360 	// called on the managed RFs in iFs.
       
   361 
       
   362 	// Even though this destructor is textually empty, it should
       
   363 	// still be exported; the compiler is generating destruction logic
       
   364 	// for us in this case
       
   365 	}
       
   366 
       
   367 void CFinder::GetNextMatchL(TDes& aMatch)
       
   368 	{
       
   369 	// ...
       
   370 	LString possible;
       
   371 	// ...
       
   372 	LCleanedupHandle<RFile> file; // We always use CleanedupXXX for locals
       
   373 	TInt status = file->Open(*iFs, possible, EFileRead); // Note use of -> and * here
       
   374 	// ...
       
   375 	aMatch = possible;
       
   376 	// ...
       
   377 	}
       
   378 @endcode
       
   379 
       
   380 For comparison, the original code in terms of existing APIs:
       
   381 
       
   382 @code
       
   383 #include <e32std.h>
       
   384 #include <f32file.h>
       
   385 
       
   386 class CFinder : public CBase
       
   387 	{
       
   388 public:
       
   389 	static CFinder* NewL(const TDesC& aPattern);
       
   390 	~CFinder();
       
   391 	void GetNextMatchL(TDes& aMatch);
       
   392 
       
   393 protected:
       
   394 	CFinder();
       
   395 	void ConstructL(const TDesC& aPattern);
       
   396 
       
   397 protected:
       
   398 	HBufC* iPattern;
       
   399 	RFs iFs;
       
   400 	// ...
       
   401 	};
       
   402 
       
   403 CFinder* CFinder::NewL(const TDesC& aPattern)
       
   404 	{
       
   405 	CFinder* self = new(ELeave) CFinder;
       
   406 	CleanupStack::PushL(self);
       
   407 	self->ConstructL(aPattern);
       
   408 	CleanupStack::Pop();
       
   409 	return self;
       
   410 	}
       
   411 
       
   412 CFinder::CFinder() 
       
   413 	{
       
   414 	}
       
   415 
       
   416 void CFinder::ConstructL(const TDesC& aPattern)
       
   417 	{
       
   418 	iPattern = aPattern.AllocL();
       
   419 	User::LeaveIfError(iFs.Connect());
       
   420 	}
       
   421 
       
   422 CFinder::~CFinder()
       
   423 	{
       
   424 	iFs.Close();
       
   425 	delete iPattern;
       
   426 	}
       
   427 
       
   428 void CFinder::GetNextMatchL(TDes& aMatch)
       
   429 	{
       
   430 	// ...
       
   431 	RFile file;
       
   432 	CleanupClosePushL(file);
       
   433 	TInt status = file.Open(iFs, possible, EFileRead);
       
   434 	// ...
       
   435 	aMatch = possible;
       
   436 	// ...
       
   437 	CleanupStack::PopAndDestroy();
       
   438 	}
       
   439 @endcode
       
   440 
       
   441 @par Q&A
       
   442 
       
   443 \b General.1 <em>Why start at the bottom? Shouldn't improving the usability of Symbian
       
   444 OS and its APIs be a top-down initiative?</em>
       
   445 
       
   446 There is a product-wide usability initiative within Symbian which aims
       
   447 to address all of APIs, documentation, and tools. On the API side,
       
   448 there are tracks that try to improve the design process for good API
       
   449 usability going forward, and tracks like this one that try to improve
       
   450 the usability of existing functionality. This is just the first
       
   451 deliverable of the latter effort, but other work is ongoing.
       
   452 
       
   453 \b General.2 <em>Will Core Idioms changes like these be backed up by tools support?</em>
       
   454 
       
   455 Yes, support for tools like Leavescan and Coverity, as well as more
       
   456 basic debugger presentation support for the new descriptor types and
       
   457 resource management classes, is being planned into the roll-out
       
   458 project.
       
   459 
       
   460 \b General.3 <em>Will Core Idioms changes like these be backed up by matching
       
   461 documentation, examples, and coding standards updates?</em>
       
   462 
       
   463 Yes, we understand this to be essential and this is our goal.
       
   464 
       
   465 \b General.4 <em>Symbian will support STL as part of Open Environment, and
       
   466 Symbian's STL implementation includes std::string and
       
   467 std::auto_ptr. Why not just use them?</em>
       
   468 
       
   469 We investigated this option to the point of creating a native Symbian
       
   470 C++ interoperable STL subset for experimentation. This was ultimately
       
   471 rejected for the following reasons:
       
   472 
       
   473 - Hybrid-style code (with mixed Symbian-style and standard-style naming) is
       
   474   harder to read and to work with than code in a single consistent style
       
   475 - Beyond basic naming conventions, supporting two very different APIs 
       
   476   for manipulating strings (the descriptor methods alongside the 
       
   477   std::string methods) similarly does not help usability
       
   478 - Interoperability between std::string and TDesC/TDes accepting APIs 
       
   479   implemented via implicit coercion is more limited than the direct placement
       
   480   of new string classes within the existing descriptor hierarchy can
       
   481   achieve
       
   482 - Because we need a number of Symbian-specific resource management 
       
   483   utilities (cleanup-stack aware, R-class aware, and so on), auto_ptr
       
   484   on its own does not provide much leverage
       
   485 - It would require maintaining two subtly variant STL builds: the Open
       
   486   Environment version with standard C++ new and exception 
       
   487   behaviour, and a Symbian C++ version with new(ELeave) and leaving
       
   488   behaviour
       
   489 
       
   490 Instead we opted to give Symbian C++ a "programming philosophy
       
   491 upgrade"; more aligned with standard C++ but still in the style of
       
   492 Symbian C++ and its existing APIs. The result is something that can be
       
   493 more easily and more incrementally adopted by existing Symbian C++
       
   494 projects and teams. Note that this decision to focus first on building
       
   495 out the usability of native Symbian C++ does not preclude the
       
   496 possibility of an official hybridized Symbian embedding of STL being
       
   497 developed at a later date
       
   498 
       
   499 Finally, we could have used Symbian-ized names like XAutoPtrYyy as the
       
   500 basis for the resource management utility classes. However, this was
       
   501 deliberately avoided because the semantics of our classes are
       
   502 different from auto_ptr e.g. they can't support copy construction or
       
   503 transfer of ownership through parameter passing and return, and
       
   504 different variants are required for use with locals than with data
       
   505 members. We did not want to give the Symbian classes names that could
       
   506 result in developers making natural but incorrect assumptions about
       
   507 their behaviour based experience with similarly-named classes
       
   508 elsewhere.
       
   509 
       
   510 \b General.5 <em>These new template classes seem more conceptually
       
   511 complex than what they're replacing. How can this improve
       
   512 usability?</em>
       
   513 
       
   514 Template classes can be complex to implement, but they're not
       
   515 particularly difficult to understand or use in the way they're
       
   516 employed here. Symbian programmers are already familiar with the
       
   517 basics from RArray<T> and RPointerArray<T>. And to anyone coming from
       
   518 standard C++ and STL it's second nature, as in fact is this general
       
   519 style of parameterised declaration to desktop Java and C# programmers
       
   520 used to generics.
       
   521 
       
   522 In the end, it's just a concise, declarative annotation that takes
       
   523 leaky code and helps turn it into robust code.
       
   524 
       
   525 Leaky:
       
   526 
       
   527 @code
       
   528 {
       
   529 CFoo* foo = CFoo::NewL();
       
   530 foo->ExecuteL(); // the CFoo leaks if this leaves
       
   531 if (foo->IsAsync())
       
   532    {
       
   533    // ...
       
   534    return; // the CFoo leaks if we return
       
   535    }
       
   536 // ...
       
   537 } // the CFoo leaks if we exit scope normally
       
   538 @endcode
       
   539 
       
   540 Safe (new style):
       
   541 
       
   542 @code
       
   543 {
       
   544 LCleanedupPtr<CFoo> foo(CFoo::NewL());
       
   545 foo->ExecuteL(); // the CFoo is automatically deleted if we leave
       
   546 if (foo->IsAsync())
       
   547    {
       
   548    // ...
       
   549    return; // the CFoo is automatically deleted if we return
       
   550    }
       
   551 // ...
       
   552 } // the CFoo is automatically deleted if we exit scope normally
       
   553 @endcode
       
   554 
       
   555 Safe (classic style):
       
   556 
       
   557 @code
       
   558 {
       
   559 CFoo* foo = CFoo::NewL();
       
   560 CleanupStack::PushL(foo);
       
   561 foo->ExecuteL(); // the CFoo is automatically deleted if we leave
       
   562 if (foo->IsAsync())
       
   563    {
       
   564    // ...
       
   565    CleanupStack::PopAndDestroy(foo); // the CFoo is deleted manually
       
   566    return; 
       
   567    }
       
   568 // ...
       
   569 CleanupStack::PopAndDestroy(foo); // the CFoo is deleted manually
       
   570 } 
       
   571 @endcode
       
   572 
       
   573 \b General.6 <em>Don't some of these APIs simply trade depth for width? There are less lines of code but the statements are longer and more complex</em>
       
   574 
       
   575 Placing as much information at point of declaration as possible guards
       
   576 against separate lines of code becoming inconsistent with one-another,
       
   577 particularly over time in the face of later code changes. Where
       
   578 cleanup code is duplicated, for example in the case of a function with
       
   579 multiple exit points, or where the cleanup point is separated by tens
       
   580 of lines of code from the creation point, these risks increase
       
   581 further.
       
   582 
       
   583 Another way to look at this is that it is far easier in a real,
       
   584 non-trivial piece of code to take an unprotected local (a raw pointer
       
   585 to an object) and to apply cleanup protection to it (for example if a
       
   586 call to a leaving function has been added) once at its point of
       
   587 creation, than it is to study what might be a quite complex flow of
       
   588 control in order to determine where all the matching calls to
       
   589 CleanupStack::PopAndDestroy() need to go. 
       
   590 
       
   591 In some cases, faced with the CleanupStack, you might actually choose
       
   592 to rework an existing function to have a single exit point to simplify
       
   593 the process of leave-protecting its code. The risks inherent in that
       
   594 are not necessary using the mode of protection offered by these new
       
   595 APIs.
       
   596 
       
   597 \b General.7 <em>These APIs seem to come with a lot of new rules,
       
   598 particularly when it comes to interoperating with existing
       
   599 functionality. If it turns out people need to understand both the new
       
   600 and old idioms in order to mix them safely, where's the benefit?
       
   601 Doesn't it actually make things worse?</em>
       
   602 
       
   603 The interoperability constraints are far from ideal, but we believe
       
   604 they are manageable and that the benefits outweigh the issues,
       
   605 particularly so for developers working on new code that uses these new
       
   606 APIs and idioms consistently. 
       
   607 
       
   608 Wherever possible sanity checking will be offered in code analysis
       
   609 tools like Leavescan and/or in UDEB runtime checking via assertions.
       
   610 
       
   611 \b Cleanedup.1 <em>The LCleanedupXxx/LManagedXxx distinction is confusing. Why can't we
       
   612 just use the same classes everywhere?</em>
       
   613 
       
   614 We would much prefer to be able to use the same classes to protect
       
   615 objects referenced from local variables as we do to project objects
       
   616 referenced from data members. In an ideal world, the LManagedXxx
       
   617 classes would be used in both scenarios (just like auto_ptr is
       
   618 elsewhere); LCleanedupXxx would not be necessary.
       
   619 
       
   620 In fact, the LManagedXxx classes can be used to protect locals if you
       
   621 wish:
       
   622 
       
   623 @code
       
   624 {
       
   625 LManagedPtr<CQuery> query(CQuery::NewL()); 
       
   626 query->BuildQueryL();
       
   627 query->ExecuteQueryL();
       
   628 } // query deleted on normal scope exit or leave
       
   629 @endcode
       
   630 
       
   631 This works fine in isolation. Unfortunately, cleanup order becomes
       
   632 counter-intuitive if calls to functions that use LManagedXxx are mixed
       
   633 with functions that use the cleanup stack with the same call stack. 
       
   634 
       
   635 Here is an example. Call order is top-to-bottom.
       
   636 
       
   637 @code
       
   638 void CFramework::StartMainLoopL()
       
   639      {
       
   640      CFramework* fw = CFramework::NewL(); 
       
   641      CleanupStack::PushL(fw); // #1
       
   642      // ...
       
   643      CleanupStack::PushL(event); // #2
       
   644      fw->DispatchL(*event);
       
   645      CleanupStack::PopAndDestroy(event);
       
   646      // ...
       
   647      CleanupStack::PopAndDestroy(fw);
       
   648      }
       
   649 
       
   650 void CFramework::DispatchL(CEvent& aEvent)
       
   651      {
       
   652      this->UserCallback()(*this, aEvent);
       
   653      }
       
   654 
       
   655 void MyUserCallback(CFramework& aFw, CEvent& aEvent)
       
   656      {
       
   657      LManagedPtr<CMyEventWrapper> myEvent(CMyEventWrapper::NewL(aEvent)); // #3
       
   658      // ...
       
   659      aFw->LookupL(arg);
       
   660      // ...
       
   661      }
       
   662 
       
   663 void CFramework::LookupL(const TDesC& aArg)
       
   664      {
       
   665      //
       
   666      CleanupStack::PushL(tmp); // #4
       
   667      // ...
       
   668      User::LeaveIfError(status);
       
   669      // ...
       
   670      CleanupStack::PopAndDestroy(tmp);
       
   671      }
       
   672 @endcode
       
   673 
       
   674 If the User::LeaveIfError() expression triggers an unhandled leave in
       
   675 the above, the cleanup order would be: #4, #2, #1, #3. If out-of-order
       
   676 execution of CMyEventWrapper's destructor can never cause problems,
       
   677 then there is not an issue. However, if CMyEventWrapper's destructor
       
   678 were to e.g. decrement a reference count on the (deleted) CEvent, this
       
   679 would lead to a panic.
       
   680 
       
   681 The cleanup order is this way because of the way User::Leave()
       
   682 processing works. It locates all pushed CleanupStack items up to the
       
   683 point of the handling TRAP and executes their cleanups. Then, finally,
       
   684 it uses C++ throw to unwind the C stack to the point of the TRAP. It
       
   685 is during C stack unwinding that the destructors for objects stored in
       
   686 locals get run, and LManagedPtr (like auto_ptr) relies exclusively on
       
   687 destructor execution to trigger cleanup.
       
   688 
       
   689 On the other hand, if MyUserCallback uses LCleanedupPtr instead of
       
   690 LManagedPtr, then its associated cleanup is triggered as part of
       
   691 CleanupStack processing and in the more intuitive sequence: #4, #3,
       
   692 #2, #1. Note that although it also has a destructor, LCleanedupPtr's
       
   693 cleanup action is only ever run once; execution of the cleanup action
       
   694 via the destructor is disabled if the cleanup action has already been
       
   695 run as part of CleanupStack processing.
       
   696 
       
   697 This is why the LCleanedupXxx classes exist. Because the situations
       
   698 where use of LManagedXxx for locals (or more precisely the resulting
       
   699 out-of-order cleanup) may cause problems are subtle to characterise,
       
   700 we guide conservatively that LCleanedupXxx should always be used to
       
   701 protect locals.
       
   702 
       
   703 \b Cleanedup.2 <em>If you are forced to call an LC method, how should you deal with it?</em>
       
   704 
       
   705 APIs should always offer pure L variants (after all, what if you want
       
   706 to store the result directly in a data member?) and this scenario
       
   707 should be rare. If it does arise, however, you have a few options.
       
   708 
       
   709 Note that code checking tools like Leavescan can flag dangerous
       
   710 combinations of LC method calls and the LCleanedupXxx classes within
       
   711 the same function.
       
   712 
       
   713 Option 1 (preferred):
       
   714 
       
   715 @code
       
   716 // Define your own popping L wrapper function
       
   717 CFoo* NewCFooL(TFooArg aArg)
       
   718        {
       
   719        CFoo* foo = CFoo::NewLC(aArg);
       
   720        CleanupStack::Pop();
       
   721        return foo;
       
   722        }
       
   723 
       
   724 // Then call that instead...
       
   725 {
       
   726 LCleanedupPtr<CFoo> foo(NewCFooL(arg));
       
   727 // ...
       
   728 }
       
   729 
       
   730 @endcode
       
   731 
       
   732 Option 2:
       
   733 
       
   734 @code
       
   735 {
       
   736 LCleanedupPtr<CFoo> foo; // pushes our "smart" cleanup item on the stack
       
   737 foo = CFoo::NewLC(arg); // leaves a classic cleanup item on the stack
       
   738 CleanupStack::Pop(); // gets rid of the classic cleanup item right away
       
   739 // ...
       
   740 }
       
   741 @endcode
       
   742 
       
   743 Never do this:
       
   744 
       
   745 @code
       
   746 {
       
   747 LCleanedupPtr<CFoo> foo(CFoo::NewLC(arg));
       
   748 // Execution order of the above statement leaves our "smart" cleanup item
       
   749 // on top of the cleanup stack and we can't get at the LC-introduced cleanup
       
   750 // item beneath it to pop it
       
   751 // ...
       
   752 }
       
   753 @endcode
       
   754 
       
   755 \b Cleanedup.3 <em>How do you create your own custom cleanup operation a la TCleanupItem?</em>
       
   756 
       
   757 The direct analog to pushing a TCleanupItem is ::LCleanedupGuard; see
       
   758 its documentation for an example of how to register a function pointer
       
   759 with argument data to get invoked on cleanup.
       
   760 
       
   761 See also #DEFINE_CLEANUP_FUNCTION and #DEFINE_CLEANUP_STRATEGY for
       
   762 creating custom cleanup operations for use with particular classes.
       
   763 
       
   764 \b Managed.1 <em>For LManagedXxx, is destruction order based on order of 
       
   765 declaration?</em>
       
   766 
       
   767 Yes, fields are destroyed (and so the cleanup operation run in the
       
   768 case of LManagedXxx fields) in reverse order of declaration as
       
   769 specified by the C++ standard.
       
   770 
       
   771 \b Managed.2 <em>Does tying cleanup order to data member order make it
       
   772 harder to maintain binary compatibility? If I want to change
       
   773 construction/destruction order I'm forced to change my header and
       
   774 reorder my data members?</em>
       
   775 
       
   776 Reordering private fields would not constitute a BC break because the
       
   777 class would not change size. In situations where your data members are
       
   778 anything other than private, including being directly revealed by
       
   779 inline methods, you always have to take great care, and will continue
       
   780 to have to do so.
       
   781 
       
   782 As a general guideline, if you are concerned about BC never make data
       
   783 members (LManagedXxx or otherwise) anything other than private. Always
       
   784 expose them via non-inline accessor methods, both to clients and to
       
   785 derived classes.
       
   786 
       
   787 \b Managed.3 <em>What happens when you mix managed and unmanaged
       
   788 pointers in the same class? Should it be avoided?</em>
       
   789 
       
   790 Your manually-written destructor code for a class will get run before
       
   791 the managed fields of that class get cleaned up, as per the C++
       
   792 standard. As long as this is understood, there is no particular reason
       
   793 to avoid mixing if it makes sense to your problem.
       
   794 
       
   795 Note, though, that if you are using single-phase construction and the
       
   796 constructor leaves, your destructor will not be run; only the
       
   797 instance's fully-constructed data members at the point of the leave
       
   798 will be destroyed.
       
   799 
       
   800 In some cases using ::LManagedGuard may be preferable to adding code
       
   801 to the destructor.
       
   802 
       
   803 \b SinglePhase.1 <em>Do you have to use single-phase construction with
       
   804 these APIs?</em>
       
   805 
       
   806 No. The primary benefit of using the LManagedXxx classes to look after
       
   807 your data members is to avoid having to write and maintain destructor
       
   808 code manually. It's fine to initialize your LManagedXxx fields by
       
   809 assignment in ConstructL if you're using two-phase construction; the
       
   810 automatic cleanup benefit is the same.
       
   811 
       
   812 The LManagedXxx classes also happen to enable the use of single-phase
       
   813 construction, but you need to consider carefully when and whether to
       
   814 use it.
       
   815 
       
   816 \b SinglePhase.2 <em>The single-phase constructor solution with
       
   817 CONSTRUCTORS_MAY_LEAVE is a bit of a mess, and not really helping to
       
   818 simplify code?</em>
       
   819 
       
   820 Yes. Unfortunately the need for #CONSTRUCTORS_MAY_LEAVE is forced by
       
   821 Symbian's legacy handling new(ELeave).
       
   822 
       
   823 \b SinglePhase.3 <em>Why and where would I ever use single-phase
       
   824 construction?</em>
       
   825 
       
   826 For classes not intended for derivation there is no issue, and it's
       
   827 quite reasonable to use the more concise single-phase construction
       
   828 idiom, typically still hidden behind a NewL.
       
   829 
       
   830 For abstract framework classes intended for derivation outside the
       
   831 defining module, the single-phase/two-phase distinction would need to
       
   832 be clearly documented and so would force awareness of at least some of
       
   833 the issues described here, even in scenarios where the deriving client
       
   834 was not intending to use the new idioms. This is probably not
       
   835 desirable.
       
   836 
       
   837 \b OrLeave.1 <em>Can you still use User::LeaveIfError() now that
       
   838 OR_LEAVE is available?  What if you want to locally-handle some error
       
   839 cases but not others.</em>
       
   840 
       
   841 Yes, #OR_LEAVE is simply a convenience macro that allows you to
       
   842 deemphasize auxiliary error checking code in most cases. You can still
       
   843 bind an error code manually, check it, and then use
       
   844 User::LeaveIfError().
       
   845 
       
   846 \b Strings.1 <em>Why derive LString from RBuf and then hide parts of
       
   847 the inherited RBuf/TDes API?</em>
       
   848 
       
   849 We want maximum interoperability with existing code and APIs for
       
   850 LString in order to maximise its usefulness. In order to achieve that
       
   851 we derive from RBuf, allowing an LString instance to be passed
       
   852 directly as a const TDesC, a TDes, or an RBuf.
       
   853 
       
   854 The trade-off is that parts of the RBuf API don't fit well with
       
   855 LString. To be conservative, we have hidden anything inherited from
       
   856 RBuf or TDes that we have found to be confusing to direct users of
       
   857 LString (you can add things later to a new API, but you can less
       
   858 easily take them away). The most obvious of these is the mass hiding
       
   859 of of the non-leaving descriptor methods for which LString provides
       
   860 leaving, auto-growing alternatives: e.g. for direct users of LString,
       
   861 we hide Append() so that it can't be used accidentally instead of
       
   862 AppendL().
       
   863 
       
   864 Note that when passed as a TDes or RBuf, and viewed through a variable
       
   865 of that type, this localised hiding within LString does not have any
       
   866 effect; existing code handed an LString will be able to manipulate it
       
   867 as it expects to.
       
   868 
       
   869 \b Strings.2 <em>Does LString support TDesC/TDes features like char*
       
   870 interop?</em>
       
   871 
       
   872 LString is an RBuf, a TDes, and a TDesC, and retains all the
       
   873 functionality of those classes.
       
   874 
       
   875 LString8 retains the same level of char* interop as existing
       
   876 descriptor classes through support for initialization from TUint8*
       
   877 zero-terminated C strings, the ZeroTerminateL() utility method, Ptr(),
       
   878 and so on.
       
   879 
       
   880 \b Strings.3 <em>Does LString auto-compress as well as auto-grow?</em>
       
   881 
       
   882 They don't. It can be hard to avoid pathologies when second-guessing
       
   883 when client code if finished with buffer capacity.
       
   884 
       
   885 */