我目前有类似的东西
QSharedPointer<QMainWindow> cv;
此共享指针用作
cV = QSharedPointer<QMainWindow>(new QMainWindow(p));
cV->setAttribute(Qt::WidgetAttribute::WA_DeleteOnClose);
cV->show();
现在,如果我关闭QMainWindow
,则以下代码会导致应用崩溃
if(cV)
cV->close(); //This pointer is no longer valid.
我的问题是,当我关闭cV
QMainWindow
对象(通过单击其中的x按钮)时,为什么以下语句返回true
if(cV)
如果Window已关闭,我如何让它返回false
?
答案 0 :(得分:4)
当你删除它指向的对象时,共享指针并不神奇地知道。手动删除其生命周期由共享指针管理的对象是错误。由于窗口在关闭时会自行删除,因此您现在可以获得悬空共享指针。
因此,您无法将QSharedPointer
与Qt::WA_DeleteOnClose
的小部件一起使用。
您需要的是一个指针,用于跟踪窗口小部件是否仍然存在。这样的指针是QPointer
,它完全符合您的需要。该指针旨在在QObject
被破坏时将自身重置为零。
请注意QPointer
是一个弱指针,当它超出范围时,它不会删除窗口。
如果您需要一个允许删除基础QObject
的拥有指针,那么就有办法:
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; }
};
由于我们允许通过除指针之外的其他方式删除对象,因此从多个线程访问对象是错误的。如果要在另一个线程中删除该对象,则在空检查和使用解除引用的对象之间存在竞争条件。因此,QPointer
或ScopedObjectPointer
只能在对象的线程中使用。这是明确断言的。 Q_ASSERT
在发布版本中成为无操作版,并且在那里没有性能影响。
答案 1 :(得分:1)
当所有所有者超出范围时,QSharedPointer保护的对象将被QSharedPointer本身删除。在您的情况下,当用户关闭cV时,您要让QMainWindow删除cV。 QSharedPointer不了解该事件,也不会自动将指针设置为0。
您的解决方案很简单。忘记QSharedPointer并使用QPointer。当您自己或通过QObject删除对象时,QPointer将自动将指针设置为0。然后,您可以使用 if(cV)。
class foo {
public:
~foo() {
delete cV; // delete cV if cV is not 0.
}
void showMainWindow() {
if ( ! cV) {
cV = new QMainWindow();
cV->setAttribute(Qt::WidgetAttribute::WA_DeleteOnClose);
}
cV->show();
}
void closeMainWindow() {
if (cV) { // cV is 0 if it is already deleted when user closes it
cV->close();
}
}
private:
QPointer<QMainWindow> cV;
};
如果您想在析构函数中避免删除并在超出范围时自动删除cV,则可以在此问题的另一个答案中使用KubarOber的ScopedQObjectPointer:< / p>
class foo {
public:
~foo() {
}
void showMainWindow() {
if ( ! cV) {
cV.reset(new QMainWindow());
cV->setAttribute(Qt::WidgetAttribute::WA_DeleteOnClose);
}
cV->show();
}
void closeMainWindow() {
if (cV) { // cV is 0 if it is already deleted when user closes it
cV->close();
}
}
private:
ScopedQObjectPointer<QMainWindow> cV;
};
编辑:我刚刚注意到您在创建cV时使用父级:新的QMainWindow(p)。好吧,如果p不为null,则p将在删除p时删除cV。因此,即使您使用QPointer,也无需在析构函数中删除cV。