source: trunk/doc/src/platforms/symbian-exceptionsafety.qdoc@ 568

Last change on this file since 568 was 561, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.1 sources.

  • Property svn:eol-style set to native
File size: 10.8 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the documentation of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
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** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42/*!
43 \page symbianexceptionsafety.html
44 \title Exception Safety with Symbian
45 \ingroup qtsymbian
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*/
Note: See TracBrowser for help on using the repository browser.