diff -r 000000000000 -r 1918ee327afb src/corelib/tools/qsharedpointer.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/corelib/tools/qsharedpointer.cpp Mon Jan 11 14:00:40 2010 +0000 @@ -0,0 +1,1505 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qsharedpointer.h" + +// to be sure we aren't causing a namespace clash: +#include "qshareddata.h" + +/*! + \class QSharedPointer + \brief The QSharedPointer class holds a strong reference to a shared pointer + \since 4.5 + + \reentrant + + The QSharedPointer is an automatic, shared pointer in C++. It + behaves exactly like a normal pointer for normal purposes, + including respect for constness. + + QSharedPointer will delete the pointer it is holding when it goes + out of scope, provided no other QSharedPointer objects are + referencing it. + + A QSharedPointer object can be created from a normal pointer, + another QSharedPointer object or by promoting a + QWeakPointer object to a strong reference. + + \section1 Thread-Safety + + QSharedPointer and QWeakPointer are thread-safe and operate + atomically on the pointer value. Different threads can also access + the same QSharedPointer or QWeakPointer object at the same time + without need for locking mechanisms. + + It should be noted that, while the pointer value can be accessed + in this manner, QSharedPointer and QWeakPointer provide no + guarantee about the object being pointed to. Thread-safety and + reentrancy rules for that object still apply. + + \section1 Other Pointer Classes + + Qt also provides two other pointer wrapper classes: QPointer and + QSharedDataPointer. They are incompatible with one another, since + each has its very different use case. + + QSharedPointer holds a shared pointer by means of an external + reference count (i.e., a reference counter placed outside the + object). Like its name indicates, the pointer value is shared + among all instances of QSharedPointer and QWeakPointer. The + contents of the object pointed to by the pointer should not + considered shared, however: there is only one object. For that + reason, QSharedPointer does not provide a way to detach or make + copies of the pointed object. + + QSharedDataPointer, on the other hand, holds a pointer to shared + data (i.e., a class derived from QSharedData). It does so by means + of an internal reference count, placed in the QSharedData base + class. This class can, therefore, detach based on the type of + access made to the data being guarded: if it's a non-const access, + it creates a copy atomically for the operation to complete. + + QExplicitlySharedDataPointer is a variant of QSharedDataPointer, except + that it only detaches if QExplicitlySharedDataPointer::detach() is + explicitly called (hence the name). + + QScopedPointer simply holds a pointer to a heap allocated object and + deletes it in its destructor. This class is useful when an object needs to + be heap allocated and deleted, but no more. QScopedPointer is lightweight, + it makes no use of additional structure or reference counting. + + Finally, QPointer holds a pointer to a QObject-derived object, but it + does so weakly. QPointer can be replaced by QWeakPointer in almost all + cases, since they have the same functionality. See + \l{QWeakPointer#tracking-qobject} for more information. + + \section1 Optional pointer tracking + + A feature of QSharedPointer that can be enabled at compile-time for + debugging purposes is a pointer tracking mechanism. When enabled, + QSharedPointer registers in a global set all the pointers that it tracks. + This allows one to catch mistakes like assigning the same pointer to two + QSharedPointer objects. + + This function is enabled by defining the \tt{QT_SHAREDPOINTER_TRACK_POINTERS} + macro before including the QSharedPointer header. + + It is safe to use this feature even with code compiled without the + feature. QSharedPointer will ensure that the pointer is removed from the + tracker even from code compiled without pointer tracking. + + Note, however, that the pointer tracking feature has limitations on + multiple- or virtual-inheritance (that is, in cases where two different + pointer addresses can refer to the same object). In that case, if a + pointer is cast to a different type and its value changes, + QSharedPointer's pointer tracking mechanism mail fail to detect that the + object being tracked is the same. + + \omit + \secton1 QSharedPointer internals + + QSharedPointer is in reality implemented by two ancestor classes: + QtSharedPointer::Basic and QtSharedPointer::ExternalRefCount. The reason + for having that split is now mostly legacy: in the beginning, + QSharedPointer was meant to support both internal reference counting and + external reference counting. + + QtSharedPointer::Basic implements the basic functionality that is shared + between internal- and external-reference counting. That is, it's mostly + the accessor functions into QSharedPointer. Those are all inherited by + QSharedPointer, which adds another level of shared functionality (the + constructors and assignment operators). The Basic class has one member + variable, which is the actual pointer being tracked. + + QtSharedPointer::ExternalRefCount implements the actual reference + counting and introduces the d-pointer for QSharedPointer. That d-pointer + itself is shared with with other QSharedPointer objects as well as + QWeakPointer. + + The reason for keeping the pointer value itself outside the d-pointer is + because of multiple inheritance needs. If you have two QSharedPointer + objects of different pointer types, but pointing to the same object in + memory, it could happen that the pointer values are different. The \tt + differentPointers autotest exemplifies this problem. The same thing could + happen in the case of virtual inheritance: a pointer of class matching + the virtual base has different address compared to the pointer of the + complete object. See the \tt virtualBaseDifferentPointers autotest for + this problem. + + The d pointer is of type QtSharedPointer::ExternalRefCountData for simple + QSharedPointer objects, but could be of a derived type in some cases. It + is basically a reference-counted reference-counter. + + \section2 d-pointer + \section3 QtSharedPointer::ExternalRefCountData + + This class is basically a reference-counted reference-counter. It has two + members: \tt strongref and \tt weakref. The strong reference counter is + controlling the lifetime of the object tracked by QSharedPointer. a + positive value indicates that the object is alive. It's also the number + of QSharedObject instances that are attached to this Data. + + When the strong reference count decreases to zero, the object is deleted + (see below for information on custom deleters). The strong reference + count can also exceptionally be -1, indicating that there are no + QSharedPointers attached to an object, which is tracked too. The only + case where this is possible is that of + \l{QWeakPointer#tracking-qobject}{QWeakPointers tracking a QObject}. + + The weak reference count controls the lifetime of the d-pointer itself. + It can be thought of as an internal/intrusive reference count for + ExternalRefCountData itself. This count is equal to the number of + QSharedPointers and QWeakPointers that are tracking this object. (In case + the object tracked derives from QObject, this number is increased by 1, + since QObjectPrivate tracks it too). + + ExternalRefCountData is a virtual class: it has a virtual destructor and + a virtual destroy() function. The destroy() function is supposed to + delete the object being tracked and return true if it does so. Otherwise, + it returns false to indicate that the caller must simply call delete. + This allows the normal use-case of QSharedPointer without custom deleters + to use only one 12- or 16-byte (depending on whether it's a 32- or 64-bit + architecture) external descriptor structure, without paying the price for + the custom deleter that it isn't using. + + \section3 QtSharedPointer::ExternalRefCountDataWithDestroyFn + + This class is not used directly, per se. It only exists to enable the two + classes that derive from it. It adds one member variable, which is a + pointer to a function (which returns void and takes an + ExternalRefCountData* as a parameter). It also overrides the destroy() + function: it calls that function pointer with \tt this as parameter, and + returns true. + + That means when ExternalRefCountDataWithDestroyFn is used, the \tt + destroyer field must be set to a valid function that \b will delete the + object tracked. + + This class also adds an operator delete function to ensure that simply + calls the global operator delete. That should be the behaviour in all + compilers already, but to be on the safe side, this class ensures that no + funny business happens. + + On a 32-bit architecture, this class is 16 bytes in size, whereas it's 24 + bytes on 64-bit. (On Itanium where function pointers contain the global + pointer, it can be 32 bytes). + + \section3 QtSharedPointer::ExternalRefCountWithCustomDeleter + + This class derives from ExternalRefCountDataWithDestroyFn and is a + template class. As template parameters, it has the type of the pointer + being tracked (\tt T) and a \tt Deleter, which is anything. It adds two + fields to its parent class, matching those template parameters: a member + of type \tt Deleter and a member of type \tt T*. + + The purpose of this class is to store the pointer to be deleted and the + deleter code along with the d-pointer. This allows the last strong + reference to call any arbitrary function that disposes of the object. For + example, this allows calling QObject::deleteLater() on a given object. + The pointer to the object is kept here to avoid the extra cost of keeping + the deleter in the generic case. + + This class is never instantiated directly: the constructors and + destructor are private. Only the create() function may be called to + return an object of this type. See below for construction details. + + The size of this class depends on the size of \tt Deleter. If it's an + empty functor (i.e., no members), ABIs generally assign it the size of 1. + But given that it's followed by a pointer, up to 3 or 7 padding bytes may + be inserted: in that case, the size of this class is 16+4+4 = 24 bytes on + 32-bit architectures, or 24+8+8 = 40 bytes on 64-bit architectures (48 + bytes on Itanium with global pointers stored). If \tt Deleter is a + function pointer, the size should be the same as the empty structure + case, except for Itanium where it may be 56 bytes due to another global + pointer. If \tt Deleter is a pointer to a member function (PMF), the size + will be even bigger and will depend on the ABI. For architectures using + the Itanium C++ ABI, a PMF is twice the size of a normal pointer, or 24 + bytes on Itanium itself. In that case, the size of this structure will be + 16+8+4 = 28 bytes on 32-bit architectures, 24+16+8 = 48 bytes on 64-bit, + and 32+24+8 = 64 bytes on Itanium. + + (Values for Itanium consider an LP64 architecture; for ILP32, pointers + are 32-bit in length, function pointers are 64-bit and PMF are 96-bit, so + the sizes are slightly less) + + \section3 QtSharedPointer::ExternalRefCountWithContiguousData + + This class also derives from ExternalRefCountDataWithDestroyFn and it is + also a template class. The template parameter is the type \tt T of the + class which QSharedPointer tracks. It adds only one member to its parent, + which is of type \tt T (the actual type, not a pointer to it). + + The purpose of this class is to lay the \tt T object out next to the + reference counts, saving one memory allocation per shared pointer. This + is particularly interesting for small \tt T or for the cases when there + are few if any QWeakPointer tracking the object. This class exists to + implement the QSharedPointer::create() call. + + Like ExternalRefCountWithCustomDeleter, this class is never instantiated + directly. This class also provides a create() member that returns the + pointer, and hides its constructors and destructor. (With C++0x, we'd + delete them). + + The size of this class depends on the size of \tt T. + + \section3 Instantiating ExternalRefCountWithCustomDeleter and ExternalRefCountWithContiguousData + + Like explained above, these classes have private constructors. Moreover, + they are not defined anywhere, so trying to call \tt{new ClassType} would + result in a compilation or linker error. Instead, these classes must be + constructed via their create() methods. + + Instead of instantiating the class by the normal way, the create() method + calls \tt{operator new} directly with the size of the class, then calls + the parent class's constructor only (ExternalRefCountDataWithDestroyFn). + This ensures that the inherited members are initialised properly, as well + as the virtual table pointer, which must point to + ExternalRefCountDataWithDestroyFn's virtual table. That way, we also + ensure that the virtual destructor being called is + ExternalRefCountDataWithDestroyFn's. + + After initialising the base class, the + ExternalRefCountWithCustomDeleter::create() function initialises the new + members directly, by using the placement \tt{operator new}. In the case + of the ExternalRefCountWithContiguousData::create() function, the address + to the still-uninitialised \tt T member is saved for the callee to use. + The member is only initialised in QSharedPointer::create(), so that we + avoid having many variants of the internal functions according to the + arguments in use for calling the constructor. + + When initialising the parent class, the create() functions pass the + address of the static deleter() member function. That is, when the + virtual destroy() is called by QSharedPointer, the deleter() functions + are called instead. These functiosn static_cast the ExternalRefCountData* + parameter to their own type and execute their deletion: for the + ExternalRefCountWithCustomDeleter::deleter() case, it runs the user's + custom deleter, then destroys the deleter; for + ExternalRefCountWithContiguousData::deleter, it simply calls the \tt T + destructor directly. + + By not calling the constructor of the derived classes, we avoid + instantiating their virtual tables. Since these classes are + template-based, there would be one virtual table per \tt T and \tt + Deleter type. (This is what Qt 4.5 did) + + Instead, only one non-inline function is required per template, which is + the deleter() static member. All the other functions can be inlined. + What's more, the address of deleter() is calculated only in code, which + can be resolved at link-time if the linker can determine that the + function lies in the current application or library module (since these + classes are not exported, that is the case for Windows or for builds with + \tt{-fvisibility=hidden}). + + In contrast, a virtual table would require at least 3 relocations to be + resolved at module load-time, per module where these classes are used. + (In the Itanium C++ ABI, there would be more relocations, due to the + RTTI) + + \section3 Modifications due to pointer-tracking + + To ensure that pointers created with pointer-tracking enabled get + un-tracked when destroyed, even if destroyed by code compiled without the + feature, QSharedPointer modifies slightly the instructions of the + previous sections. + + When ExternalRefCountWithCustomDeleter or + ExternalRefCountWithContiguousData are used, their create() functions + will set the ExternalRefCountDataWithDestroyFn::destroyer function + pointer to safetyCheckDeleter() instead. These static member functions + simply call internalSafetyCheckRemove2() before passing control to the + normal deleter() function. + + If neither custom deleter nor QSharedPointer::create() are used, then + QSharedPointer uses a custom deleter of its own: the normalDeleter() + function, which simply calls \tt delete. By using a custom deleter, the + safetyCheckDeleter() procedure described above kicks in. + + \endomit + + \sa QSharedDataPointer, QWeakPointer, QScopedPointer +*/ + +/*! + \class QWeakPointer + \brief The QWeakPointer class holds a weak reference to a shared pointer + \since 4.5 + \reentrant + + The QWeakPointer is an automatic weak reference to a + pointer in C++. It cannot be used to dereference the pointer + directly, but it can be used to verify if the pointer has been + deleted or not in another context. + + QWeakPointer objects can only be created by assignment from a + QSharedPointer. The exception is pointers derived from QObject: in that + case, QWeakPointer serves as a replacement to QPointer. + + It's important to note that QWeakPointer provides no automatic casting + operators to prevent mistakes from happening. Even though QWeakPointer + tracks a pointer, it should not be considered a pointer itself, since it + doesn't guarantee that the pointed object remains valid. + + Therefore, to access the pointer that QWeakPointer is tracking, you must + first promote it to QSharedPointer and verify if the resulting object is + null or not. QSharedPointer guarantees that the object isn't deleted, so + if you obtain a non-null object, you may use the pointer. See + QWeakPointer::toStrongRef() for more an example. + + QWeakPointer also provides the QWeakPointer::data() method that returns + the tracked pointer without ensuring that it remains valid. This function + is provided if you can guarantee by external means that the object will + not get deleted (or if you only need the pointer value) and the cost of + creating a QSharedPointer using toStrongRef() is too high. + + That function can also be used to obtain the tracked pointer for + QWeakPointers that cannot be promoted to QSharedPointer, such as those + created directly from a QObject pointer (not via QSharedPointer). + + \section1 Tracking QObject + + QWeakPointer can be used to track deletion classes derives from QObject, + even if they are not managed by QSharedPointer. When used in that role, + QWeakPointer replaces the older QPointer in all use-cases. QWeakPointer + is also more efficient than QPointer, so it should be preferred in all + new code. + + To do that, QWeakPointer provides a special constructor that is only + available if the template parameter \tt T is either QObject or a class + deriving from it. Trying to use that constructor if \tt T does not derive + from QObject will result in compilation errors. + + To obtain the QObject being tracked by QWeakPointer, you must use the + QWeakPointer::data() function, but only if you can guarantee that the + object cannot get deleted by another context. It should be noted that + QPointer had the same constraint, so use of QWeakPointer forces you to + consider whether the pointer is still valid. + + QObject-derived classes can only be deleted in the thread they have + affinity to (which is the thread they were created in or moved to, using + QObject::moveToThread()). In special, QWidget-derived classes cannot be + created in non-GUI threads nor moved there. Therefore, guaranteeing that + the tracked QObject has affinity to the current thread is enough to also + guarantee that it won't be deleted asynchronously. + + Note that QWeakPointer's size and data layout do not match QPointer, so + it cannot replace that class in a binary-compatible manner. + + Care must also be taken with QWeakPointers created directly from QObject + pointers when dealing with code that was compiled with Qt versions prior + to 4.6. Those versions may not track the reference counters correctly, so + QWeakPointers created from QObject should never be passed to code that + hasn't been recompiled. + + \omit + \secton1 QWeakPointer internals + + QWeakPointer shares most of its internal functionality with + \l{QSharedPointer#qsharedpointer-internals}{QSharedPointer}, so see that + class's internal documentation for more information. + + QWeakPointer requires an external reference counter in order to operate. + Therefore, it is incompatible by design with \l QSharedData-derived + classes. + + It has a special QObject constructor, which works by calling + QtSharedPointer::ExternalRefCountData::getAndRef, which retrieves the + d-pointer from QObjectPrivate. If one isn't set yet, that function + creates the d-pointer and atomically sets it. + + If getAndRef needs to create a d-pointer, it sets the strongref to -1, + indicating that the QObject is not shared: QWeakPointer is used only to + determine whether the QObject has been deleted. In that case, it cannot + be upgraded to QSharedPointer (see the previous section). + + \endomit + + \sa QSharedPointer, QScopedPointer +*/ + +/*! + \fn QSharedPointer::QSharedPointer() + + Creates a QSharedPointer that points to null (0). +*/ + +/*! + \fn QSharedPointer::~QSharedPointer() + + Destroys this QSharedPointer object. If it is the last reference to + the pointer stored, this will delete the pointer as well. +*/ + +/*! + \fn QSharedPointer::QSharedPointer(T *ptr) + + Creates a QSharedPointer that points to \a ptr. The pointer \a ptr + becomes managed by this QSharedPointer and must not be passed to + another QSharedPointer object or deleted outside this object. +*/ + +/*! + \fn QSharedPointer::QSharedPointer(T *ptr, Deleter deleter) + + Creates a QSharedPointer that points to \a ptr. The pointer \a ptr + becomes managed by this QSharedPointer and must not be passed to + another QSharedPointer object or deleted outside this object. + + The \a deleter paramter specifies the custom deleter for this + object. The custom deleter is called when the strong reference + count drops to 0 instead of the operator delete(). This is useful, + for instance, for calling deleteLater() in a QObject instead: + + \code + static void doDeleteLater(MyObject *obj) + { + obj->deleteLater(); + } + + void otherFunction() + { + QSharedPointer obj = + QSharedPointer(new MyObject, doDeleteLater); + + // continue using obj + obj.clear(); // calls obj->deleteLater(); + } + \endcode + + It is also possible to specify a member function directly, as in: + \code + QSharedPointer obj = + QSharedPointer(new MyObject, &QObject::deleteLater); + \endcode + + \sa clear() +*/ + +/*! + \fn QSharedPointer::QSharedPointer(const QSharedPointer &other) + + Creates a QSharedPointer object that shares \a other's pointer. + + If \tt T is a derived type of the template parameter of this class, + QSharedPointer will perform an automatic cast. Otherwise, you will + get a compiler error. +*/ + +/*! + \fn QSharedPointer::QSharedPointer(const QWeakPointer &other) + + Creates a QSharedPointer by promoting the weak reference \a other + to strong reference and sharing its pointer. + + If \tt T is a derived type of the template parameter of this + class, QSharedPointer will perform an automatic cast. Otherwise, + you will get a compiler error. + + \sa QWeakPointer::toStrongRef() +*/ + +/*! + \fn QSharedPointer &QSharedPointer::operator=(const QSharedPointer &other) + + Makes this object share \a other's pointer. The current pointer + reference is discarded and, if it was the last, the pointer will + be deleted. + + If \tt T is a derived type of the template parameter of this + class, QSharedPointer will perform an automatic cast. Otherwise, + you will get a compiler error. +*/ + +/*! + \fn QSharedPointer &QSharedPointer::operator=(const QWeakPointer &other) + + Promotes \a other to a strong reference and makes this object + share a reference to the pointer referenced by it. The current pointer + reference is discarded and, if it was the last, the pointer will + be deleted. + + If \tt T is a derived type of the template parameter of this + class, QSharedPointer will perform an automatic cast. Otherwise, + you will get a compiler error. +*/ + +/*! + \fn T *QSharedPointer::data() const + + Returns the value of the pointer referenced by this object. + + Note: do not delete the pointer returned by this function or pass + it to another function that could delete it, including creating + QSharedPointer or QWeakPointer objects. +*/ + +/*! + \fn T &QSharedPointer::operator *() const + + Provides access to the shared pointer's members. + + \sa isNull() +*/ + +/*! + \fn T *QSharedPointer::operator ->() const + + Provides access to the shared pointer's members. + + \sa isNull() +*/ + +/*! + \fn bool QSharedPointer::isNull() const + + Returns true if this object is holding a reference to a null + pointer. +*/ + +/*! + \fn QSharedPointer::operator bool() const + + Returns true if this object is not null. This function is suitable + for use in \tt if-constructs, like: + + \code + if (sharedptr) { ... } + \endcode + + \sa isNull() +*/ + +/*! + \fn bool QSharedPointer::operator !() const + + Returns true if this object is null. This function is suitable + for use in \tt if-constructs, like: + + \code + if (!sharedptr) { ... } + \endcode + + \sa isNull() +*/ + +/*! + \fn QSharedPointer QSharedPointer::staticCast() const + + Performs a static cast from this pointer's type to \tt X and returns + a QSharedPointer that shares the reference. This function can be + used for up- and for down-casting, but is more useful for + up-casting. + + Note: the template type \c X must have the same const and volatile + qualifiers as the template of this object, or the cast will + fail. Use constCast() if you need to drop those qualifiers. + + \sa dynamicCast(), constCast(), qSharedPointerCast() +*/ + +/*! + \fn QSharedPointer QSharedPointer::dynamicCast() const + + Performs a dynamic cast from this pointer's type to \tt X and + returns a QSharedPointer that shares the reference. If this + function is used to up-cast, then QSharedPointer will perform a \tt + dynamic_cast, which means that if the object being pointed by this + QSharedPointer is not of type \tt X, the returned object will be + null. + + Note: the template type \c X must have the same const and volatile + qualifiers as the template of this object, or the cast will + fail. Use constCast() if you need to drop those qualifiers. + + \sa qSharedPointerDynamicCast() +*/ + +/*! + \fn QSharedPointer QSharedPointer::constCast() const + + Performs a \tt const_cast from this pointer's type to \tt X and returns + a QSharedPointer that shares the reference. This function can be + used for up- and for down-casting, but is more useful for + up-casting. + + \sa isNull(), qSharedPointerConstCast() +*/ + +/*! + \fn QSharedPointer QSharedPointer::objectCast() const + \since 4.6 + + Performs a \l qobject_cast() from this pointer's type to \tt X and + returns a QSharedPointer that shares the reference. If this + function is used to up-cast, then QSharedPointer will perform a \tt + qobject_cast, which means that if the object being pointed by this + QSharedPointer is not of type \tt X, the returned object will be + null. + + Note: the template type \c X must have the same const and volatile + qualifiers as the template of this object, or the cast will + fail. Use constCast() if you need to drop those qualifiers. + + \sa qSharedPointerObjectCast() +*/ + +/*! + \fn QWeakPointer QSharedPointer::toWeakRef() const + + Returns a weak reference object that shares the pointer referenced + by this object. + + \sa QWeakPointer::QWeakPointer() +*/ + +/*! + \fn void QSharedPointer::clear() + + Clears this QSharedPointer object, dropping the reference that it + may have had to the pointer. If this was the last reference, then + the pointer itself will be deleted. +*/ + +/*! + \fn QWeakPointer::QWeakPointer() + + Creates a QWeakPointer that points to nothing. +*/ + +/*! + \fn QWeakPointer::~QWeakPointer() + + Destroys this QWeakPointer object. The pointer referenced + by this object will not be deleted. +*/ + +/*! + \fn QWeakPointer::QWeakPointer(const QWeakPointer &other) + + Creates a QWeakPointer that holds a weak reference to the + pointer referenced by \a other. + + If \tt T is a derived type of the template parameter of this + class, QWeakPointer will perform an automatic cast. Otherwise, + you will get a compiler error. +*/ + +/*! + \fn QWeakPointer::QWeakPointer(const QSharedPointer &other) + + Creates a QWeakPointer that holds a weak reference to the + pointer referenced by \a other. + + If \tt T is a derived type of the template parameter of this + class, QWeakPointer will perform an automatic cast. Otherwise, + you will get a compiler error. +*/ + +/*! + \fn QWeakPointer::QWeakPointer(const QObject *obj) + \since 4.6 + + Creates a QWeakPointer that holds a weak reference directly to the + QObject \a obj. This constructor is only available if the template type + \tt T is QObject or derives from it (otherwise a compilation error will + result). + + You can use this constructor with any QObject, even if they were not + created with \l QSharedPointer. + + Note that QWeakPointers created this way on arbitrary QObjects usually + cannot be promoted to QSharedPointer. + + \sa QSharedPointer, QWeakPointer#tracking-qobject +*/ + +/*! + \fn QWeakPointer &QWeakPointer::operator=(const QObject *obj) + \since 4.6 + + Makes this QWeakPointer hold a weak reference to directly to the QObject + \a obj. This function is only available if the template type \tt T is + QObject or derives from it. + + \sa QWeakPointer#tracking-qobject +*/ + +/*! + \fn QWeakPointer &QWeakPointer::operator=(const QWeakPointer &other) + + Makes this object share \a other's pointer. The current pointer + reference is discarded but is not deleted. + + If \tt T is a derived type of the template parameter of this + class, QWeakPointer will perform an automatic cast. Otherwise, + you will get a compiler error. +*/ + +/*! + \fn QWeakPointer &QWeakPointer::operator=(const QSharedPointer &other) + + Makes this object share \a other's pointer. The current pointer + reference is discarded but is not deleted. + + If \tt T is a derived type of the template parameter of this + class, QWeakPointer will perform an automatic cast. Otherwise, + you will get a compiler error. +*/ + +/*! + \fn bool QWeakPointer::isNull() const + + Returns true if this object is holding a reference to a null + pointer. + + Note that, due to the nature of weak references, the pointer that + QWeakPointer references can become null at any moment, so + the value returned from this function can change from false to + true from one call to the next. +*/ + +/*! + \fn QWeakPointer::operator bool() const + + Returns true if this object is not null. This function is suitable + for use in \tt if-constructs, like: + + \code + if (weakref) { ... } + \endcode + + Note that, due to the nature of weak references, the pointer that + QWeakPointer references can become null at any moment, so + the value returned from this function can change from true to + false from one call to the next. + + \sa isNull() +*/ + +/*! + \fn bool QWeakPointer::operator !() const + + Returns true if this object is null. This function is suitable + for use in \tt if-constructs, like: + + \code + if (!weakref) { ... } + \endcode + + Note that, due to the nature of weak references, the pointer that + QWeakPointer references can become null at any moment, so + the value returned from this function can change from false to + true from one call to the next. + + \sa isNull() +*/ + +/*! + \fn T *QWeakPointer::data() const + \since 4.6 + + Returns the value of the pointer being tracked by this QWeakPointer, + \b without ensuring that it cannot get deleted. To have that guarantee, + use toStrongRef(), which returns a QSharedPointer object. If this + function can determine that the pointer has already been deleted, it + returns 0. + + It is ok to obtain the value of the pointer and using that value itself, + like for example in debugging statements: + + \code + qDebug("Tracking %p", weakref.data()); + \endcode + + However, dereferencing the pointer is only allowed if you can guarantee + by external means that the pointer does not get deleted. For example, + if you can be certain that no other thread can delete it, nor the + functions that you may call. + + If that is the case, then the following code is valid: + + \code + // this pointer cannot be used in another thread + // so other threads cannot delete it + QWeakPointer weakref = obtainReference(); + + Object *obj = weakref.data(); + if (obj) { + // if the pointer wasn't deleted yet, we know it can't get + // deleted by our own code here nor the functions we call + otherFunction(obj); + } + \endcode + + Use this function with care. + + \sa isNull(), toStrongRef() +*/ + +/*! + \fn QSharedPointer QWeakPointer::toStrongRef() const + + Promotes this weak reference to a strong one and returns a + QSharedPointer object holding that reference. When promoting to + QSharedPointer, this function verifies if the object has been deleted + already or not. If it hasn't, this function increases the reference + count to the shared object, thus ensuring that it will not get + deleted. + + Since this function can fail to obtain a valid strong reference to the + shared object, you should always verify if the conversion succeeded, + by calling QSharedPointer::isNull() on the returned object. + + For example, the following code promotes a QWeakPointer that was held + to a strong reference and, if it succeeded, it prints the value of the + integer that was held: + + \code + QWeakPointer weakref; + + // ... + + QSharedPointer strong = weakref.toStrongRef(); + if (strong) + qDebug() << "The value is:" << *strong; + else + qDebug() << "The value has already been deleted"; + \endcode + + \sa QSharedPointer::QSharedPointer() +*/ + +/*! + \fn void QWeakPointer::clear() + + Clears this QWeakPointer object, dropping the reference that it + may have had to the pointer. +*/ + +/*! + \fn bool operator==(const QSharedPointer &ptr1, const QSharedPointer &ptr2) + \relates QSharedPointer + + Returns true if the pointer referenced by \a ptr1 is the + same pointer as that referenced by \a ptr2. + + If \a ptr2's template parameter is different from \a ptr1's, + QSharedPointer will attempt to perform an automatic \tt static_cast + to ensure that the pointers being compared are equal. If \a ptr2's + template parameter is not a base or a derived type from + \a ptr1's, you will get a compiler error. +*/ + +/*! + \fn bool operator!=(const QSharedPointer &ptr1, const QSharedPointer &ptr2) + \relates QSharedPointer + + Returns true if the pointer referenced by \a ptr1 is not the + same pointer as that referenced by \a ptr2. + + If \a ptr2's template parameter is different from \a ptr1's, + QSharedPointer will attempt to perform an automatic \tt static_cast + to ensure that the pointers being compared are equal. If \a ptr2's + template parameter is not a base or a derived type from + \a ptr1's, you will get a compiler error. +*/ + +/*! + \fn bool operator==(const QSharedPointer &ptr1, const X *ptr2) + \relates QSharedPointer + + Returns true if the pointer referenced by \a ptr1 is the + same pointer as \a ptr2. + + If \a ptr2's type is different from \a ptr1's, + QSharedPointer will attempt to perform an automatic \tt static_cast + to ensure that the pointers being compared are equal. If \a ptr2's + type is not a base or a derived type from this + \a ptr1's, you will get a compiler error. +*/ + +/*! + \fn bool operator!=(const QSharedPointer &ptr1, const X *ptr2) + \relates QSharedPointer + + Returns true if the pointer referenced by \a ptr1 is not the + same pointer as \a ptr2. + + If \a ptr2's type is different from \a ptr1's, + QSharedPointer will attempt to perform an automatic \tt static_cast + to ensure that the pointers being compared are equal. If \a ptr2's + type is not a base or a derived type from this + \a ptr1's, you will get a compiler error. +*/ + +/*! + \fn bool operator==(const T *ptr1, const QSharedPointer &ptr2) + \relates QSharedPointer + + Returns true if the pointer \a ptr1 is the + same pointer as that referenced by \a ptr2. + + If \a ptr2's template parameter is different from \a ptr1's type, + QSharedPointer will attempt to perform an automatic \tt static_cast + to ensure that the pointers being compared are equal. If \a ptr2's + template parameter is not a base or a derived type from + \a ptr1's type, you will get a compiler error. +*/ + +/*! + \fn bool operator!=(const T *ptr1, const QSharedPointer &ptr2) + \relates QSharedPointer + + Returns true if the pointer \a ptr1 is not the + same pointer as that referenced by \a ptr2. + + If \a ptr2's template parameter is different from \a ptr1's type, + QSharedPointer will attempt to perform an automatic \tt static_cast + to ensure that the pointers being compared are equal. If \a ptr2's + template parameter is not a base or a derived type from + \a ptr1's type, you will get a compiler error. +*/ + +/*! + \fn bool operator==(const QSharedPointer &ptr1, const QWeakPointer &ptr2) + \relates QWeakPointer + + Returns true if the pointer referenced by \a ptr1 is the + same pointer as that referenced by \a ptr2. + + If \a ptr2's template parameter is different from \a ptr1's, + QSharedPointer will attempt to perform an automatic \tt static_cast + to ensure that the pointers being compared are equal. If \a ptr2's + template parameter is not a base or a derived type from + \a ptr1's, you will get a compiler error. +*/ + +/*! + \fn bool operator!=(const QSharedPointer &ptr1, const QWeakPointer &ptr2) + \relates QWeakPointer + + Returns true if the pointer referenced by \a ptr1 is not the + same pointer as that referenced by \a ptr2. + + If \a ptr2's template parameter is different from \a ptr1's, + QSharedPointer will attempt to perform an automatic \tt static_cast + to ensure that the pointers being compared are equal. If \a ptr2's + template parameter is not a base or a derived type from + \a ptr1's, you will get a compiler error. +*/ + +/*! + \fn bool operator==(const QWeakPointer &ptr1, const QSharedPointer &ptr2) + \relates QWeakPointer + + Returns true if the pointer referenced by \a ptr1 is the + same pointer as that referenced by \a ptr2. + + If \a ptr2's template parameter is different from \a ptr1's, + QSharedPointer will attempt to perform an automatic \tt static_cast + to ensure that the pointers being compared are equal. If \a ptr2's + template parameter is not a base or a derived type from + \a ptr1's, you will get a compiler error. +*/ + +/*! + \fn bool operator!=(const QWeakPointer &ptr1, const QSharedPointer &ptr2) + \relates QWeakPointer + + Returns true if the pointer referenced by \a ptr1 is not the + same pointer as that referenced by \a ptr2. + + If \a ptr2's template parameter is different from \a ptr1's, + QSharedPointer will attempt to perform an automatic \tt static_cast + to ensure that the pointers being compared are equal. If \a ptr2's + template parameter is not a base or a derived type from + \a ptr1's, you will get a compiler error. +*/ + +/*! + \fn QSharedPointer qSharedPointerCast(const QSharedPointer &other) + \relates QSharedPointer + + Returns a shared pointer to the pointer held by \a other, cast to + type \tt X. The types \tt T and \tt X must belong to one + hierarchy for the \tt static_cast to succeed. + + Note that \tt X must have the same cv-qualifiers (\tt const and + \tt volatile) that \tt T has, or the code will fail to + compile. Use qSharedPointerConstCast to cast away the constness. + + \sa QSharedPointer::staticCast(), qSharedPointerDynamicCast(), qSharedPointerConstCast() +*/ + +/*! + \fn QSharedPointer qSharedPointerCast(const QWeakPointer &other) + \relates QSharedPointer + \relates QWeakPointer + + Returns a shared pointer to the pointer held by \a other, cast to + type \tt X. The types \tt T and \tt X must belong to one + hierarchy for the \tt static_cast to succeed. + + The \a other object is converted first to a strong reference. If + that conversion fails (because the object it's pointing to has + already been deleted), this function returns a null + QSharedPointer. + + Note that \tt X must have the same cv-qualifiers (\tt const and + \tt volatile) that \tt T has, or the code will fail to + compile. Use qSharedPointerConstCast to cast away the constness. + + \sa QWeakPointer::toStrongRef(), qSharedPointerDynamicCast(), qSharedPointerConstCast() +*/ + +/*! + \fn QSharedPointer qSharedPointerDynamicCast(const QSharedPointer &other) + \relates QSharedPointer + + Returns a shared pointer to the pointer held by \a other, using a + dynamic cast to type \tt X to obtain an internal pointer of the + appropriate type. If the \tt dynamic_cast fails, the object + returned will be null. + + Note that \tt X must have the same cv-qualifiers (\tt const and + \tt volatile) that \tt T has, or the code will fail to + compile. Use qSharedPointerConstCast to cast away the constness. + + \sa QSharedPointer::dynamicCast(), qSharedPointerCast(), qSharedPointerConstCast() +*/ + +/*! + \fn QSharedPointer qSharedPointerDynamicCast(const QWeakPointer &other) + \relates QSharedPointer + \relates QWeakPointer + + Returns a shared pointer to the pointer held by \a other, using a + dynamic cast to type \tt X to obtain an internal pointer of the + appropriate type. If the \tt dynamic_cast fails, the object + returned will be null. + + The \a other object is converted first to a strong reference. If + that conversion fails (because the object it's pointing to has + already been deleted), this function also returns a null + QSharedPointer. + + Note that \tt X must have the same cv-qualifiers (\tt const and + \tt volatile) that \tt T has, or the code will fail to + compile. Use qSharedPointerConstCast to cast away the constness. + + \sa QWeakPointer::toStrongRef(), qSharedPointerCast(), qSharedPointerConstCast() +*/ + +/*! + \fn QSharedPointer qSharedPointerConstCast(const QSharedPointer &other) + \relates QSharedPointer + + Returns a shared pointer to the pointer held by \a other, cast to + type \tt X. The types \tt T and \tt X must belong to one + hierarchy for the \tt const_cast to succeed. The \tt const and \tt + volatile differences between \tt T and \tt X are ignored. + + \sa QSharedPointer::constCast(), qSharedPointerCast(), qSharedPointerDynamicCast() +*/ + +/*! + \fn QSharedPointer qSharedPointerConstCast(const QWeakPointer &other) + \relates QSharedPointer + \relates QWeakPointer + + Returns a shared pointer to the pointer held by \a other, cast to + type \tt X. The types \tt T and \tt X must belong to one + hierarchy for the \tt const_cast to succeed. The \tt const and + \tt volatile differences between \tt T and \tt X are ignored. + + The \a other object is converted first to a strong reference. If + that conversion fails (because the object it's pointing to has + already been deleted), this function returns a null + QSharedPointer. + + \sa QWeakPointer::toStrongRef(), qSharedPointerCast(), qSharedPointerDynamicCast() +*/ + +/*! + \fn QSharedPointer qSharedPointerObjectCast(const QSharedPointer &other) + \relates QSharedPointer + \since 4.6 + + \brief The qSharedPointerObjectCast function is for casting a shared pointer. + + Returns a shared pointer to the pointer held by \a other, using a + \l qobject_cast() to type \tt X to obtain an internal pointer of the + appropriate type. If the \tt qobject_cast fails, the object + returned will be null. + + Note that \tt X must have the same cv-qualifiers (\tt const and + \tt volatile) that \tt T has, or the code will fail to + compile. Use qSharedPointerConstCast to cast away the constness. + + \sa QSharedPointer::objectCast(), qSharedPointerCast(), qSharedPointerConstCast() +*/ + +/*! + \fn QSharedPointer qSharedPointerObjectCast(const QWeakPointer &other) + \relates QSharedPointer + \relates QWeakPointer + \since 4.6 + + \brief The qSharedPointerObjectCast function is for casting a shared pointer. + + Returns a shared pointer to the pointer held by \a other, using a + \l qobject_cast() to type \tt X to obtain an internal pointer of the + appropriate type. If the \tt qobject_cast fails, the object + returned will be null. + + The \a other object is converted first to a strong reference. If + that conversion fails (because the object it's pointing to has + already been deleted), this function also returns a null + QSharedPointer. + + Note that \tt X must have the same cv-qualifiers (\tt const and + \tt volatile) that \tt T has, or the code will fail to + compile. Use qSharedPointerConstCast to cast away the constness. + + \sa QWeakPointer::toStrongRef(), qSharedPointerCast(), qSharedPointerConstCast() +*/ + + +/*! + \fn QWeakPointer qWeakPointerCast(const QWeakPointer &other) + \relates QWeakPointer + + Returns a weak pointer to the pointer held by \a other, cast to + type \tt X. The types \tt T and \tt X must belong to one + hierarchy for the \tt static_cast to succeed. + + Note that \tt X must have the same cv-qualifiers (\tt const and + \tt volatile) that \tt T has, or the code will fail to + compile. Use qSharedPointerConstCast to cast away the constness. +*/ + +#include +#include + +#if !defined(QT_NO_QOBJECT) +#include "private/qobject_p.h" + +QT_BEGIN_NAMESPACE + +/*! + \internal + This function is called for a just-created QObject \a obj, to enable + the use of QSharedPointer and QWeakPointer. + + When QSharedPointer is active in a QObject, the object must not be deleted + directly: the lifetime is managed by the QSharedPointer object. In that case, + the deleteLater() and parent-child relationship in QObject only decrease + the strong reference count, instead of deleting the object. +*/ +void QtSharedPointer::ExternalRefCountData::setQObjectShared(const QObject *obj, bool) +{ + Q_ASSERT(obj); + QObjectPrivate *d = QObjectPrivate::get(const_cast(obj)); + + if (d->sharedRefcount) + qFatal("QSharedPointer: pointer %p already has reference counting", obj); + d->sharedRefcount = this; + + // QObject decreases the refcount too, so increase it up + weakref.ref(); +} + +QtSharedPointer::ExternalRefCountData *QtSharedPointer::ExternalRefCountData::getAndRef(const QObject *obj) +{ + Q_ASSERT(obj); + QObjectPrivate *d = QObjectPrivate::get(const_cast(obj)); + Q_ASSERT_X(!d->wasDeleted, "QWeakPointer", "Detected QWeakPointer creation in a QObject being deleted"); + + ExternalRefCountData *that = d->sharedRefcount; + if (that) { + that->weakref.ref(); + return that; + } + + // we can create the refcount data because it doesn't exist + ExternalRefCountData *x = new ExternalRefCountData(Qt::Uninitialized); + x->strongref = -1; + x->weakref = 2; // the QWeakPointer that called us plus the QObject itself + if (!d->sharedRefcount.testAndSetRelease(0, x)) { + delete x; + d->sharedRefcount->weakref.ref(); + } + return d->sharedRefcount; +} + +QT_END_NAMESPACE + +#endif + + + +#if !defined(QT_NO_MEMBER_TEMPLATES) + +//# define QT_SHARED_POINTER_BACKTRACE_SUPPORT +# ifdef QT_SHARED_POINTER_BACKTRACE_SUPPORT +# if defined(__GLIBC__) && (__GLIBC__ >= 2) && !defined(__UCLIBC__) && !defined(QT_LINUXBASE) +# define BACKTRACE_SUPPORTED +# elif defined(Q_OS_MACX) +# define BACKTRACE_SUPPORTED +# endif +# endif + +# if defined(BACKTRACE_SUPPORTED) +# include +# include +# include +# include +# include + +QT_BEGIN_NAMESPACE + +static inline QByteArray saveBacktrace() __attribute__((always_inline)); +static inline QByteArray saveBacktrace() +{ + static const int maxFrames = 32; + + QByteArray stacktrace; + stacktrace.resize(sizeof(void*) * maxFrames); + int stack_size = backtrace((void**)stacktrace.data(), maxFrames); + stacktrace.resize(sizeof(void*) * stack_size); + + return stacktrace; +} + +static void printBacktrace(QByteArray stacktrace) +{ + void *const *stack = (void *const *)stacktrace.constData(); + int stack_size = stacktrace.size() / sizeof(void*); + char **stack_symbols = backtrace_symbols(stack, stack_size); + + int filter[2]; + pid_t child = -1; + if (pipe(filter) != -1) + child = fork(); + if (child == 0) { + // child process + dup2(fileno(stderr), fileno(stdout)); + dup2(filter[0], fileno(stdin)); + close(filter[0]); + close(filter[1]); + execlp("c++filt", "c++filt", "-n", NULL); + + // execlp failed + execl("/bin/cat", "/bin/cat", NULL); + _exit(127); + } + + // parent process + close(filter[0]); + FILE *output; + if (child == -1) { + // failed forking + close(filter[1]); + output = stderr; + } else { + output = fdopen(filter[1], "w"); + } + + fprintf(stderr, "Backtrace of the first creation (most recent frame first):\n"); + for (int i = 0; i < stack_size; ++i) { + if (strlen(stack_symbols[i])) + fprintf(output, "#%-2d %s\n", i, stack_symbols[i]); + else + fprintf(output, "#%-2d %p\n", i, stack[i]); + } + + if (child != -1) { + fclose(output); + waitpid(child, 0, 0); + } +} + +QT_END_NAMESPACE + +# endif // BACKTRACE_SUPPORTED + +namespace { + QT_USE_NAMESPACE + struct Data { + const volatile void *pointer; +# ifdef BACKTRACE_SUPPORTED + QByteArray backtrace; +# endif + }; + + class KnownPointers + { + public: + QMutex mutex; + QHash dPointers; + QHash dataPointers; + }; +} + +Q_GLOBAL_STATIC(KnownPointers, knownPointers) + +QT_BEGIN_NAMESPACE + +namespace QtSharedPointer { + Q_CORE_EXPORT void internalSafetyCheckAdd(const volatile void *); + Q_CORE_EXPORT void internalSafetyCheckRemove(const volatile void *); + Q_AUTOTEST_EXPORT void internalSafetyCheckCleanCheck(); +} + +/*! + \internal +*/ +void QtSharedPointer::internalSafetyCheckAdd(const volatile void *) +{ + // Qt 4.5 compatibility + // this function is broken by design, so it was replaced with internalSafetyCheckAdd2 + // + // it's broken because we tracked the pointers added and + // removed from QSharedPointer, converted to void*. + // That is, this is supposed to track the "top-of-object" pointer in + // case of multiple inheritance. + // + // However, it doesn't work well in some compilers: + // if you create an object with a class of type A and the last reference + // is dropped of type B, then the value passed to internalSafetyCheckRemove could + // be different than was added. That would leave dangling addresses. + // + // So instead, we track the pointer by the d-pointer instead. +} + +/*! + \internal +*/ +void QtSharedPointer::internalSafetyCheckRemove(const volatile void *) +{ + // Qt 4.5 compatibility + // see comments above +} + +/*! + \internal +*/ +void QtSharedPointer::internalSafetyCheckAdd2(const void *d_ptr, const volatile void *ptr) +{ + // see comments above for the rationale for this function + KnownPointers *const kp = knownPointers(); + if (!kp) + return; // end-game: the application is being destroyed already + + QMutexLocker lock(&kp->mutex); + Q_ASSERT(!kp->dPointers.contains(d_ptr)); + + //qDebug("Adding d=%p value=%p", d_ptr, ptr); + + const void *other_d_ptr = kp->dataPointers.value(ptr, 0); + if (other_d_ptr) { +# ifdef BACKTRACE_SUPPORTED + printBacktrace(knownPointers()->dPointers.value(other_d_ptr).backtrace); +# endif + qFatal("QSharedPointer: internal self-check failed: pointer %p was already tracked " + "by another QSharedPointer object %p", ptr, other_d_ptr); + } + + Data data; + data.pointer = ptr; +# ifdef BACKTRACE_SUPPORTED + data.backtrace = saveBacktrace(); +# endif + + kp->dPointers.insert(d_ptr, data); + kp->dataPointers.insert(ptr, d_ptr); + Q_ASSERT(kp->dPointers.size() == kp->dataPointers.size()); +} + +/*! + \internal +*/ +void QtSharedPointer::internalSafetyCheckRemove2(const void *d_ptr) +{ + KnownPointers *const kp = knownPointers(); + if (!kp) + return; // end-game: the application is being destroyed already + + QMutexLocker lock(&kp->mutex); + + QHash::iterator it = kp->dPointers.find(d_ptr); + if (it == kp->dPointers.end()) { + qFatal("QSharedPointer: internal self-check inconsistency: pointer %p was not tracked. " + "To use QT_SHAREDPOINTER_TRACK_POINTERS, you have to enable it throughout " + "in your code.", d_ptr); + } + + QHash::iterator it2 = kp->dataPointers.find(it->pointer); + Q_ASSERT(it2 != kp->dataPointers.end()); + + //qDebug("Removing d=%p value=%p", d_ptr, it->pointer); + + // remove entries + kp->dataPointers.erase(it2); + kp->dPointers.erase(it); + Q_ASSERT(kp->dPointers.size() == kp->dataPointers.size()); +} + +/*! + \internal + Called by the QSharedPointer autotest +*/ +void QtSharedPointer::internalSafetyCheckCleanCheck() +{ +# ifdef QT_BUILD_INTERNAL + KnownPointers *const kp = knownPointers(); + Q_ASSERT_X(kp, "internalSafetyCheckSelfCheck()", "Called after global statics deletion!"); + + if (kp->dPointers.size() != kp->dataPointers.size()) + qFatal("Internal consistency error: the number of pointers is not equal!"); + + if (!kp->dPointers.isEmpty()) + qFatal("Pointer cleaning failed: %d entries remaining", kp->dPointers.size()); +# endif +} + +QT_END_NAMESPACE + +#endif