QSharedPointer не возвращает false

У меня сейчас что-то вроде этого

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)

Как я могу вернуть его false если окно было закрыто?

1

Решение

Общий указатель не знает, когда вы удаляете объект, на который он указывает. это ошибка вручную удалить объект, срок жизни которого управляется общим указателем. Поскольку окно само удаляется, когда оно закрывается, теперь вы получаете висячие общие указатели.

Ergo, вы не можете использовать 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 становится неактивным в сборках релизов и не оказывает никакого влияния на производительность.

4

Другие решения

Объект, охраняемый QSharedPointer, предназначен для удаления самим QSharedPointer, когда все владельцы выходят из области видимости. В вашем случае вы позволяете QMainWindow удалять cV, когда пользователь закрывает его. QSharedPointer не знает об этом инциденте и не установит указатель на 0 автоматически.

Ваше решение простое. Забудьте о QSharedPointer и просто используйте QPointer. QPointer автоматически установит указатель на 0, когда объект будет удален вами или QObject. Вы можете использовать если (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’s ScopedQObjectPointer в другом ответе на этот вопрос:

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 не нуль, тогда p удалит cV, когда p удален. Поэтому нет необходимости удалять cV в деструкторе, даже если вы используете QPointer.

1

По вопросам рекламы [email protected]