doc/src/platforms/symbian-exceptionsafety.qdoc
branchRCL_3
changeset 8 3f74d0d4af4c
equal deleted inserted replaced
6:dee5afe5301f 8:3f74d0d4af4c
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2010 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 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 */