| /**************************************************************************** |
| ** |
| ** Copyright (C) 2016 The Qt Company Ltd. |
| ** Contact: https://www.qt.io/licensing/ |
| ** |
| ** 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 The Qt Company. For licensing terms |
| ** and conditions see https://www.qt.io/terms-conditions. For further |
| ** information use the contact form at https://www.qt.io/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: https://www.gnu.org/licenses/fdl-1.3.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); |
| ... |
| int ret; |
| try { |
| ret = app.exec(); |
| } catch (const std::bad_alloc &) { |
| // clean up here, e.g. save the session |
| // and close all config files. |
| |
| return EXIT_FAILURE; // exit the application |
| } |
| ... |
| return ret; |
| \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 |
| |
| */ |