Symbian3/SDK/Source/GUID-F686965A-13E5-5C0A-AED1-55EC91C79433.dita
author Dominic Pinkman <Dominic.Pinkman@Nokia.com>
Thu, 21 Jan 2010 18:18:20 +0000
changeset 0 89d6a7a84779
permissions -rw-r--r--
Initial contribution of Documentation_content according to Feature bug 1266 bug 1268 bug 1269 bug 1270 bug 1372 bug 1374 bug 1375 bug 1379 bug 1380 bug 1381 bug 1382 bug 1383 bug 1385

<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (c) 2007-2010 Nokia Corporation and/or its subsidiary(-ies) All rights reserved. -->
<!-- This component and the accompanying materials are made available under the terms of the License 
"Eclipse Public License v1.0" which accompanies this distribution, 
and is available at the URL "http://www.eclipse.org/legal/epl-v10.html". -->
<!-- Initial Contributors:
    Nokia Corporation - initial contribution.
Contributors: 
-->
<!DOCTYPE concept
  PUBLIC "-//OASIS//DTD DITA Concept//EN" "concept.dtd">
<concept id="GUID-F686965A-13E5-5C0A-AED1-55EC91C79433" xml:lang="en"><title>Restrictions
on the use of leaves and TRAPs in destructors</title><shortdesc>Outlines the restrictions on the use of leaves and TRAPs in destructors.</shortdesc><prolog><metadata><keywords/></metadata></prolog><conbody>
<p>You <i>cannot</i> use <xref href="GUID-3F2CDC74-2568-371C-9D8E-34A66A619226.dita"><apiname>TRAP</apiname></xref> (and <xref href="GUID-57895C34-AD00-35E1-9BF8-478653056383.dita"><apiname>TRAPD</apiname></xref>)
and <xref href="GUID-C197C9A7-EA05-3F24-9854-542E984C612D.dita#GUID-C197C9A7-EA05-3F24-9854-542E984C612D/GUID-ABF0FC5C-3334-3761-893D-D836B2EE0541"><apiname>User::Leave()</apiname></xref> in a destructor, nor in any function
that a destructor might call, for objects that have been placed onto the call
stack. <xref href="GUID-3F2CDC74-2568-371C-9D8E-34A66A619226.dita"><apiname>TRAP</apiname></xref> and <xref href="GUID-C197C9A7-EA05-3F24-9854-542E984C612D.dita#GUID-C197C9A7-EA05-3F24-9854-542E984C612D/GUID-ABF0FC5C-3334-3761-893D-D836B2EE0541"><apiname>User::Leave()</apiname></xref> are implemented
in terms of C++ Try, Catch and Throw. This means that if an exception occurs,
the call stack is "unwound". In doing this, the destructors of objects on
the call stack are called. If any of these destructors subsequently throw
an exception, this is termed a nested exception. While a nested exception
is supported on the emulator (WINS), it is not supported on other hardware,
and there is no guarantee that the thread will terminate cleanly. </p>
<p>Symbian coding standards state that objects placed onto the call stack
should not have non-trivial destructors. By convention, such classes are identified
by names having an initial T or R. This means that such destructors should
not leave. </p>
<p>The following code fragment shows the kind of code that is <i>not safe</i> to
use: </p>
<codeblock id="GUID-7B2BD496-6F99-5586-B320-DB7C5DC490B9" xml:space="preserve">void f()  
    {
    TBar bar;
    // Function processing.
    ...
    // The bar object on the call stack is automatically destroyed
    // at function termination.
    }

TBar::~TBar()
    {
    // The destructor calls a function that can leave.
    // This is not permitted here.
    doCleanUpL();
    }</codeblock>
<p>You <i>can</i> use <xref href="GUID-3F2CDC74-2568-371C-9D8E-34A66A619226.dita"><apiname>TRAP</apiname></xref> (and <xref href="GUID-57895C34-AD00-35E1-9BF8-478653056383.dita"><apiname>TRAPD</apiname></xref>)
and <xref href="GUID-C197C9A7-EA05-3F24-9854-542E984C612D.dita#GUID-C197C9A7-EA05-3F24-9854-542E984C612D/GUID-ABF0FC5C-3334-3761-893D-D836B2EE0541"><apiname>User::Leave()</apiname></xref> in a destructor and in any function that
a destructor might call, for heap-based objects, i.e. objects that are destroyed
by the cleanup stack. However, while this is permissible, it is not recommended
practice. </p>
<p>Such objects are instances of classes derived from <xref href="GUID-8F6FE089-E2A8-30F4-B67E-10F286347681.dita"><apiname>CBase</apiname></xref>,
and by convention such classes are identified by names having have an initial
C. </p>
<p>In principle, a destructor should never fail. If a destructor can leave,
or a function called by the destructor can leave, it suggests that the code
has been poorly architected. It also implies that part of the destruction
process might fail, potentially leading to memory or handle leaks. </p>
<p>One possible approach to avoid using functions that can leave within a
destructor is to have what might be referred to as ‘two-phase destruction’
where some form of <codeph>ShutdownL</codeph> function is called prior to
deleting the object. If there are concerns about introducing additional complexities
in API-usage (and greater risk), suitable guards can be introduced. One method
might be to store the current state of the object internally and then use
an ASSERT to check this in the destructor. This would ensure that any usage
errors are discovered by very simple run time testing. </p>
<p>The following code fragment shows an example of two-phase destruction. </p>
<codeblock id="GUID-BA3B57D6-913F-5AEC-A7AB-4EE6B915127A" xml:space="preserve">// Here, the shutdown function is a member of the class CMyClass,
// and performs destruction activity that can leave.

class CMyClass : public CBase
    {
public :
    IMPORT_C ~CMyClass();
    IMPORT_C void ShutdownL();
    ...
private :
    TBool iStateActive
    ...
    }

EXPORT_C void CMyClass::ShutdownL()
    {
       if (iStateActive == ETrue)
              {
              // Some destruction activity that can leave.
              iStateActive = EFalse;
              }
    }

EXPORT_C CMyClass::~CMyClass()
    {
       // Assert to ensure that ShutdownL() has already been called.
       ASSERT(iStateActive == EFalse);
    }
</codeblock>
</conbody></concept>