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

Last change on this file since 865 was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

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