summaryrefslogtreecommitdiff
path: root/doc/src/howtos/exceptionsafety.qdoc
blob: 39354974b4e1598c19abbcc940e7226cbb1e94c1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the documentation of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:FDL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Free Documentation License Usage
** Alternatively, this file may be used under the terms of the GNU Free
** Documentation License version 1.3 as published by the Free Software
** Foundation and appearing in the file included in the packaging of
** this file.  Please review the following information to ensure
** the GNU Free Documentation License version 1.3 requirements
** will be met: http://www.gnu.org/copyleft/fdl.html.
** $QT_END_LICENSE$
**
****************************************************************************/

/*!
    \page exceptionsafety.html
    \title Exception Safety
    \ingroup best-practices
    \brief A guide to exception safety in Qt.

    \b {Preliminary warning}: Exception safety is not feature complete!
    Common cases should work, but classes might still leak or even crash.

    Qt itself will not throw exceptions. Instead, error codes are used.
    In addition, some classes have user visible error messages, for example
    \l QIODevice::errorString() or \l QSqlQuery::lastError().
    This has historical and practical reasons - turning on exceptions
    can increase the library size by over 20%.

    The following sections describe Qt's behavior if exception support is
    enabled at compile time.

    \tableofcontents

    \section1 Exception Safe Modules

    \section2 Containers

    Qt's \l{container classes} are generally exception neutral. They pass any
    exception that happens within their contained type \c T to the user
    while keeping their internal state valid.

    Example:

    \code
    QList<QString> list;
    ...
    try {
        list.append("hello");
    } catch (...) {
    }
    // list is safe to use - the exception did not affect it.
    \endcode

    Exceptions to that rule are containers for types that can throw during assignment
    or copy constructions. For those types, functions that modify the container as well as
    returning a value, are unsafe to use:

    \code
    MyType s = list.takeAt(2);
    \endcode

    If an exception occurs during the assignment of \c s, the value at index 2 is already
    removed from the container, but hasn't been assigned to \c s yet. It is lost
    without chance of recovery.

    The correct way to write it:

    \code
    MyType s = list.at(2);
    list.removeAt(2);
    \endcode

    If the assignment throws, the container will still contain the value; no data loss occurred.

    Note that implicitly shared Qt classes will not throw in their assignment
    operators or copy constructors, so the limitation above does not apply.

    \section1 Out of Memory Handling

    Most desktop operating systems overcommit memory. This means that \c malloc()
    or \c{operator new} return a valid pointer, even though there is not enough
    memory available at allocation time. On such systems, no exception of type
    \c std::bad_alloc is thrown.

    On all other operating systems, Qt will throw an exception of type std::bad_alloc
    if any allocation fails. Allocations can fail if the system runs out of memory or
    doesn't have enough continuous memory to allocate the requested size.

    Exceptions to that rule are documented. As an example, QImage constructors will
    create a \l{QImage::isNull()}{null} image if not enough memory exists instead
    of throwing an exception.

    \section1 Recovering from Exceptions

    Currently, the only supported use case for recovering from exceptions thrown
    within Qt (for example due to out of memory) is to exit the event loop and do
    some cleanup before exiting the application.

    Typical use case:

    \code
    QApplication app(argc, argv);
    ...
    try {
        app.exec();
    } catch (const std::bad_alloc &) {
        // clean up here, e.g. save the session
        // and close all config files.

        return 0; // exit the application
    }
    \endcode

    After an exception is thrown, the connection to the windowing server
    might already be closed. It is not safe to call a GUI related function
    after catching an exception.

    \section1 Exceptions in Client Code

    \section2 Signals and Slots

    Throwing an exception from a slot invoked by Qt's \l{Signals & Slots}{signal-slot}
    connection mechanism is considered undefined behaviour, unless it is handled within the slot:

    \code
    State state;
    StateListener stateListener;

    // OK; the exception is handled before it leaves the slot.
    QObject::connect(&state, SIGNAL(stateChanged()), &stateListener, SLOT(throwHandledException()));
    // Undefined behaviour; upon invocation of the slot, the exception will be propagated to the
    // point of emission, unwinding the stack of the Qt code (which is not guaranteed to be exception safe).
    QObject::connect(&state, SIGNAL(stateChanged()), &stateListener, SLOT(throwUnhandledException()));
    \endcode

    If the slot was invoked directly, like a regular function call, exceptions may be used.
    This is because the connection mechanism is bypassed when invoking slots directly:

    \code
    State state;
    StateListener stateListener;

    // ...

    try {
        // OK; invoking slot directly.
        stateListener.throwException();
    } catch (...) {
        qDebug() << "Handling exception not caught in slot.";
    }
    \endcode

*/