A shared pointer doesn't magically know when you delete the object it points to. It is an error to manually delete an object whose lifetime is managed by a shared pointer. Since the window self-deletes when it gets closed, you now get dangling shared pointers.
Ergo, you can't use QSharedPointer
with a widget that is Qt::WA_DeleteOnClose
.
What you need is a pointer that tracks whether the widget still exists. Such pointer is QPointer
, it does exactly what you need. That pointer is designed to reset itself to zero when a QObject
gets destroyed.
Note that QPointer
is a weak pointer, it won't delete the window when it goes out of scope.
If you need an owning pointer that allows deletion of the underlying QObject
, there's a way to do it:
template <typename T> class ScopedQObjectPointer {
Q_DISABLE_COPY(ScopedQObjectPointer)
QPointer<T> m_ptr;
inline void check() const {
Q_ASSERT(m_ptr && (m_ptr->thread() == 0
|| m_ptr->thread() == QThread::currentThread()));
}
public:
explicit ScopedQObjectPointer(T* obj = 0) : m_ptr(obj) {}
ScopedQObjectPointer(ScopedQObjectPointer &&other) : m_ptr(other.take()) {}
~ScopedQObjectPointer() { check(); delete m_ptr; }
operator T*() const { check(); return m_ptr; }
T & operator*() const { check(); return *m_ptr; }
T * operator->() const { check(); return m_ptr; }
T * data() const { check(); return m_ptr; }
T * take() { check(); T * p = m_ptr; m_ptr.clear(); return p; }
void reset(T * other) { check(); delete m_ptr; m_ptr = other; }
operator bool() const { check(); return m_ptr; }
};
Since we allow the deletion of the object through other means than the pointer, it is an error to access the object from multiple threads. If the object were to be deleted in another thread, there's a race condition between the null check and the use of dereferenced object. Thus, a QPointer
, or a ScopedObjectPointer
can only be used from object's thread. This is explicitly asserted. The Q_ASSERT
becomes a no-op in release builds and has no performance impact there.