|
1 /**************************************************************************** |
|
2 ** |
|
3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). |
|
4 ** All rights reserved. |
|
5 ** Contact: Nokia Corporation (qt-info@nokia.com) |
|
6 ** |
|
7 ** This file is part of the documentation of the Qt Toolkit. |
|
8 ** |
|
9 ** $QT_BEGIN_LICENSE:LGPL$ |
|
10 ** No Commercial Usage |
|
11 ** This file contains pre-release code and may not be distributed. |
|
12 ** You may use this file in accordance with the terms and conditions |
|
13 ** contained in the Technology Preview License Agreement accompanying |
|
14 ** this package. |
|
15 ** |
|
16 ** GNU Lesser General Public License Usage |
|
17 ** Alternatively, this file may be used under the terms of the GNU Lesser |
|
18 ** General Public License version 2.1 as published by the Free Software |
|
19 ** Foundation and appearing in the file LICENSE.LGPL included in the |
|
20 ** packaging of this file. Please review the following information to |
|
21 ** ensure the GNU Lesser General Public License version 2.1 requirements |
|
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
|
23 ** |
|
24 ** In addition, as a special exception, Nokia gives you certain additional |
|
25 ** rights. These rights are described in the Nokia Qt LGPL Exception |
|
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
|
27 ** |
|
28 ** If you have questions regarding the use of this file, please contact |
|
29 ** Nokia at qt-info@nokia.com. |
|
30 ** |
|
31 ** |
|
32 ** |
|
33 ** |
|
34 ** |
|
35 ** |
|
36 ** |
|
37 ** |
|
38 ** $QT_END_LICENSE$ |
|
39 ** |
|
40 ****************************************************************************/ |
|
41 |
|
42 /*! |
|
43 \page symbianexceptionsafety.html |
|
44 \title Exception Safety with Symbian |
|
45 \ingroup qts60 |
|
46 \brief A guide to integrating exception safety in Qt with Symbian. |
|
47 |
|
48 The following sections describe how Qt code can interoperate with Symbian's |
|
49 exception safety system. |
|
50 |
|
51 \tableofcontents |
|
52 |
|
53 \section1 What the problem is |
|
54 |
|
55 Qt and Symbian have different exception systems. Qt works with standard C++ |
|
56 exceptions, whereas Symbian has its TRAP/Leave/CleanupStack system. So, what would |
|
57 happen if you mix the two systems? It could go wrong in a number of ways. |
|
58 |
|
59 Clean-up ordering would be different between the two. When Symbian code |
|
60 leaves, the clean-up stack is cleaned up before anything else happens. After |
|
61 that, the objects on the call stack would be cleaned up as with a normal |
|
62 exception. So if there are any dependencies between stack-based and |
|
63 objects owned by the clean-up stack, there could be problems due to this |
|
64 ordering. |
|
65 |
|
66 Symbian's \c XLeaveException, which is used when Symbian implements leaves as |
|
67 exceptions, is not derived from \c std::exception, so would not be caught in |
|
68 Qt catch statements designed to catch \c std::exception. |
|
69 |
|
70 Qt's and standard C++'s \c std::exception derived exceptions result in program |
|
71 termination if they fall back to a Symbian TRAP. |
|
72 |
|
73 These problems can be solved with barrier macros and helper functions that |
|
74 will translate between the two exception systems. Use them, in Qt code, |
|
75 whenever calling into or being called from Symbian code. |
|
76 |
|
77 \section1 Qt calls to Symbian |
|
78 |
|
79 When calling Symbian leaving functions from Qt code, we want to translate |
|
80 Symbian leaves to standard C++ exceptions. The following help is provided: |
|
81 |
|
82 \list |
|
83 \o \l qt_symbian_throwIfError() takes a Symbian |
|
84 error code and throws an appropriate exception to represent it. |
|
85 This will do nothing if the error code is not in fact an error. The |
|
86 function is equivalent to Symbian's \c User::LeaveIfError. |
|
87 \o \l q_check_ptr() takes a pointer and throws a std::bad_alloc |
|
88 exception if it is 0, otherwise the pointer is returned. This can be |
|
89 used to check the success of a non-throwing allocation, eg from |
|
90 \c malloc(). The function is equivalent to Symbian's \c |
|
91 User::LeaveIfNull. |
|
92 \o \l QT_TRAP_THROWING() takes a Symbian leaving |
|
93 code fragment f and runs it under a trap harness converting any resulting |
|
94 error into an exception. |
|
95 \o \c TRAP and \c TRAPD from the Symbian libraries can be used to convert |
|
96 leaves to error codes. |
|
97 \endlist |
|
98 |
|
99 \code |
|
100 HBufC* buf=0; |
|
101 // this will throw a std::bad_alloc because we've asked for too much memory |
|
102 QT_TRAP_THROWING(buf = HBufC::NewL(100000000)); |
|
103 |
|
104 _LIT(KStr,"abc"); |
|
105 TInt pos = KStr().Locate('c'); |
|
106 // pos is a good value, >= 0, so no exception is thrown |
|
107 qt_symbian_throwIfError(pos); |
|
108 |
|
109 pos = KStr().Locate('d'); |
|
110 // pos == KErrNotFound, so this throws an exception |
|
111 qt_symbian_throwIfError(pos); |
|
112 |
|
113 // we are asking for a lot of memory, HBufC::New may return NULL, so check it |
|
114 HBufC *buffer = q_check_ptr(HBufC::New(1000000)); |
|
115 \endcode |
|
116 |
|
117 \section2 Be careful with new and CBase |
|
118 |
|
119 When writing Qt code, \c new will normally throw a \c std::bad_alloc if the |
|
120 allocation fails. However this may not happen if the object being created |
|
121 has its own \c {operator new}. For example, CBase and derived classes have |
|
122 their own \c {operator new} which returns 0 and the \c {new(ELeave)} |
|
123 overload for a leaving \c {operator new}, neither of which does what we want. |
|
124 When using 2-phase construction of CBase derived objects, use \c new and |
|
125 \l q_check_ptr(). |
|
126 |
|
127 \oldcode |
|
128 CFbsBitmap* fbsBitmap = new(ELeave) CFbsBitmap; |
|
129 \newcode |
|
130 CFbsBitmap* fbsBitmap = q_check_ptr(new CFbsBitmap); |
|
131 \endcode |
|
132 |
|
133 \section1 Qt called from Symbian |
|
134 |
|
135 When Qt code is called from Symbian, we want to translate standard C++ |
|
136 exceptions to Symbian leaves or error codes. The following help is |
|
137 provided: |
|
138 |
|
139 \list |
|
140 \o \l qt_symbian_exception2Error() - |
|
141 this takes a standard exception and gives an appropriate Symbian |
|
142 error code. If no mapping is known for the exception type, |
|
143 \c KErrGeneral is returned. |
|
144 \o \l qt_symbian_exception2LeaveL() - |
|
145 this takes a standard exception and generates an appropriate Symbian |
|
146 leave. |
|
147 \o \l QT_TRYCATCH_ERROR() - this macro |
|
148 takes the standard C++ code fragment \c f, catches any std::exceptions |
|
149 thrown from it, and sets err to the corresponding Symbian error code. |
|
150 err is set to \c KErrNone otherwise. |
|
151 \o \l QT_TRYCATCH_LEAVING() - this macro takes the |
|
152 standard C++ code fragment \c f, catches any std::exceptions thrown from |
|
153 it, and throws a corresponding Symbian leave. |
|
154 \endlist |
|
155 |
|
156 \code |
|
157 TInt DoTickL() // called from an active object RunL, ie Symbian leaves expected |
|
158 { |
|
159 // without the translation to Symbian Leave, we get a USER:0 panic |
|
160 QT_TRYCATCH_LEAVING({ |
|
161 int* x = new int[100000000]; // compiled as Qt code, will throw std::bad_alloc |
|
162 delete [] x; |
|
163 }); |
|
164 return 0; |
|
165 } |
|
166 \endcode |
|
167 |
|
168 \section1 Common sense things |
|
169 |
|
170 Try to minimise the interleaving of Symbian and Qt code, every switch |
|
171 requires a barrier. Grouping the code styles in different blocks will |
|
172 minimise the problems. For instance, examine the following code. |
|
173 |
|
174 \code |
|
175 1. TRAPD(err, m_playUtility = CMdaAudioPlayerUtility::NewL(*this); |
|
176 2. QString filepath = QFileInfo( m_sound->fileName() ).absoluteFilePath(); |
|
177 3. filepath = QDir::toNativeSeparators(filepath); |
|
178 4. m_playUtility->OpenFileL(qt_QString2TPtrC(filepath))); |
|
179 \endcode |
|
180 |
|
181 Line 1 starts a Symbian leave handling block, which is good because it |
|
182 also uses a Symbian leave generating function. |
|
183 |
|
184 Line 2 creates a \l QString, uses \l QFileInfo and various member functions. |
|
185 These could all throw exceptions, which is not good inside a \c TRAP block. |
|
186 |
|
187 Line 3 is unclear as to whether it might throw an exception, but since |
|
188 it's dealing with strings it probably does, again bad. |
|
189 |
|
190 Line 4 is tricky, it calls a leaving function which is ok within a \c TRAP, |
|
191 but it also uses a helper function to convert string types. In this case |
|
192 the helper function may cause an unwelcome exception. |
|
193 |
|
194 We could rewrite this with nested exception translations, but it's much |
|
195 easier to refactor it. |
|
196 |
|
197 \code |
|
198 QString filepath = QFileInfo( m_sound->fileName() ).absoluteFilePath(); |
|
199 filepath = QDir::toNativeSeparators(filepath); |
|
200 TPtrC filepathPtr(qt_QString2TPtrC(filepath)); |
|
201 TRAPD(err, m_playUtility = CMdaAudioPlayerUtility::NewL(*this); |
|
202 m_playUtility->OpenFileL(filepathPtr)); |
|
203 \endcode |
|
204 |
|
205 Now the exception generating functions are separated from the leaving |
|
206 functions. |
|
207 |
|
208 \section1 Advanced technique |
|
209 When using Symbian APIs in Qt code, you may find that Symbian leaving |
|
210 code and Qt exception throwing code are just too mixed up to have |
|
211 them interoperate through barriers. In some circumstances you can allow |
|
212 code to both leave and throw exceptions. But you must be aware of the |
|
213 following issues: |
|
214 |
|
215 \list |
|
216 \o Depending on whether a leave or exception is thrown, or a normal |
|
217 exit happens, the cleanup order will vary. If the code leaves, |
|
218 cleanup stack cleanup will happen first. On an exception however, |
|
219 cleanup stack cleanup will happen last. |
|
220 \o There must not be any destructor dependencies between different |
|
221 code styles. That is, you must not have symbian objects using Qt |
|
222 objects in their destructors, and vice versa. This is because the |
|
223 cleanup order varies, and may result in objects being used after |
|
224 they are deleted. |
|
225 \o The cleanup stack must not refer to any stack based object. For |
|
226 instance, in Symbian you may use \c CleanupClosePushL() to push |
|
227 stack based R-classes onto the cleanup stack. However if the |
|
228 stack has unwound due to an exception before the cleanup stack |
|
229 cleanup happens, stack based objects will now be invalid. |
|
230 Instead of using the cleanup stack, consider Symbian's new |
|
231 \c LManagedHandle<> (or a custom cleanup object) to tie R-class |
|
232 cleanup to the stack. |
|
233 \o Mixed throwing code must be called within both a TRAP and a |
|
234 try/catch harness. Standard exceptions must not propagate to |
|
235 the TRAP and cleanup stack cleanup will only happen if a leave |
|
236 is thrown, so the correct pattern is either \c {TRAPD(err, |
|
237 QT_TRYCATCH_LEAVING( f ));} or \c {QT_TRAP_THROWING( |
|
238 QT_TRYCATCH_LEAVING( f ));}, depending if you want an error |
|
239 code or exception as a result. |
|
240 \endlist |
|
241 */ |