|
1 <?xml version="1.0" encoding="utf-8"?> |
|
2 <!-- Copyright (c) 2007-2010 Nokia Corporation and/or its subsidiary(-ies) All rights reserved. --> |
|
3 <!-- This component and the accompanying materials are made available under the terms of the License |
|
4 "Eclipse Public License v1.0" which accompanies this distribution, |
|
5 and is available at the URL "http://www.eclipse.org/legal/epl-v10.html". --> |
|
6 <!-- Initial Contributors: |
|
7 Nokia Corporation - initial contribution. |
|
8 Contributors: |
|
9 --> |
|
10 <!DOCTYPE concept |
|
11 PUBLIC "-//OASIS//DTD DITA Concept//EN" "concept.dtd"> |
|
12 <concept id="GUID-F686965A-13E5-5C0A-AED1-55EC91C79433" xml:lang="en"><title>Restrictions |
|
13 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> |
|
14 <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>) |
|
15 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 |
|
16 that a destructor might call, for objects that have been placed onto the call |
|
17 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 |
|
18 in terms of C++ Try, Catch and Throw. This means that if an exception occurs, |
|
19 the call stack is "unwound". In doing this, the destructors of objects on |
|
20 the call stack are called. If any of these destructors subsequently throw |
|
21 an exception, this is termed a nested exception. While a nested exception |
|
22 is supported on the emulator (WINS), it is not supported on other hardware, |
|
23 and there is no guarantee that the thread will terminate cleanly. </p> |
|
24 <p>Symbian coding standards state that objects placed onto the call stack |
|
25 should not have non-trivial destructors. By convention, such classes are identified |
|
26 by names having an initial T or R. This means that such destructors should |
|
27 not leave. </p> |
|
28 <p>The following code fragment shows the kind of code that is <i>not safe</i> to |
|
29 use: </p> |
|
30 <codeblock id="GUID-7B2BD496-6F99-5586-B320-DB7C5DC490B9" xml:space="preserve">void f() |
|
31 { |
|
32 TBar bar; |
|
33 // Function processing. |
|
34 ... |
|
35 // The bar object on the call stack is automatically destroyed |
|
36 // at function termination. |
|
37 } |
|
38 |
|
39 TBar::~TBar() |
|
40 { |
|
41 // The destructor calls a function that can leave. |
|
42 // This is not permitted here. |
|
43 doCleanUpL(); |
|
44 }</codeblock> |
|
45 <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>) |
|
46 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 |
|
47 a destructor might call, for heap-based objects, i.e. objects that are destroyed |
|
48 by the cleanup stack. However, while this is permissible, it is not recommended |
|
49 practice. </p> |
|
50 <p>Such objects are instances of classes derived from <xref href="GUID-8F6FE089-E2A8-30F4-B67E-10F286347681.dita"><apiname>CBase</apiname></xref>, |
|
51 and by convention such classes are identified by names having have an initial |
|
52 C. </p> |
|
53 <p>In principle, a destructor should never fail. If a destructor can leave, |
|
54 or a function called by the destructor can leave, it suggests that the code |
|
55 has been poorly architected. It also implies that part of the destruction |
|
56 process might fail, potentially leading to memory or handle leaks. </p> |
|
57 <p>One possible approach to avoid using functions that can leave within a |
|
58 destructor is to have what might be referred to as ‘two-phase destruction’ |
|
59 where some form of <codeph>ShutdownL</codeph> function is called prior to |
|
60 deleting the object. If there are concerns about introducing additional complexities |
|
61 in API-usage (and greater risk), suitable guards can be introduced. One method |
|
62 might be to store the current state of the object internally and then use |
|
63 an ASSERT to check this in the destructor. This would ensure that any usage |
|
64 errors are discovered by very simple run time testing. </p> |
|
65 <p>The following code fragment shows an example of two-phase destruction. </p> |
|
66 <codeblock id="GUID-BA3B57D6-913F-5AEC-A7AB-4EE6B915127A" xml:space="preserve">// Here, the shutdown function is a member of the class CMyClass, |
|
67 // and performs destruction activity that can leave. |
|
68 |
|
69 class CMyClass : public CBase |
|
70 { |
|
71 public : |
|
72 IMPORT_C ~CMyClass(); |
|
73 IMPORT_C void ShutdownL(); |
|
74 ... |
|
75 private : |
|
76 TBool iStateActive |
|
77 ... |
|
78 } |
|
79 |
|
80 EXPORT_C void CMyClass::ShutdownL() |
|
81 { |
|
82 if (iStateActive == ETrue) |
|
83 { |
|
84 // Some destruction activity that can leave. |
|
85 iStateActive = EFalse; |
|
86 } |
|
87 } |
|
88 |
|
89 EXPORT_C CMyClass::~CMyClass() |
|
90 { |
|
91 // Assert to ensure that ShutdownL() has already been called. |
|
92 ASSERT(iStateActive == EFalse); |
|
93 } |
|
94 </codeblock> |
|
95 </conbody></concept> |