Подтвердить что ты не робот

В чем разница между классами QPointer, QSharedPointer и QWeakPointer в Qt?

Я прочитал из Qt-документации о классах QPointer, QSharedPointer и QWeakPointer. В нем говорится:

  • QPointer - это шаблонный класс, который предоставляет защищенные указатели на объекты Qt и ведет себя как обычный указатель на С++, за исключением того, что он автоматически устанавливается в 0, когда объект, на который ссылается, уничтожается и не создается "оборванных указателей".

  • QSharedPointer класс содержит сильную ссылку на общий указатель.

  • QWeakPointer класс содержит слабую ссылку на общий указатель.

Мои вопросы: "В чем разница между этими классами?". В чем разница между указателем на объект и ссылкой на указатель? Все ли они указывают на объекты с различными механизмами и поведением?

4b9b3361

Ответ 1

QPointer:
QPointer может указывать только на экземпляры QObject. Он будет автоматически установлен на nullptr, если указанный объект будет уничтожен. Это слабый указатель, специализированный для QObject.

Рассмотрим этот фрагмент:

QObject *obj = new QObject;
QPointer<QObject> pObj(obj);
delete obj;
Q_ASSERT(pObj.isNull()); // pObj will be nullptr now

QSharedPointer
Указатель с подсчетом ссылок. Фактический объект будет удален только после уничтожения всех общих указателей. Эквивалентно std::shared_ptr.

int *pI = new int;
QSharedPointer<int> pI1(pI);
QSharedPointer<int> pI2 = pI1;
pI1.clear();
// pI2 is still pointing to pI, so it is not deleted
pI2.clear();
// No shared pointers anymore, pI is deleted

Обратите внимание, что при наличии общего указателя объект не удаляется!

QWeakPointer:
Может содержать слабую ссылку на общий указатель. Это не помешает уничтожению объекта, а просто сбрасывается. Эквивалентен std::weak_ptr, где lock эквивалентен toStrongRef.

int *pI = new int;
QSharedPointer<int> pI1(pI);
QWeakPointer<int> pI2 = pI1;
pI1.clear();
// No shared pointers anymore, pI is deleted
//
// To use the shared pointer, we must "lock" it for use:
QSharedPointer<int> pI2_locked = pI2.toStrongRef();
Q_ASSERT(pI2_locked.isNull());

Это можно использовать, если вам нужен доступ к объекту, который контролируется другим модулем.

Чтобы использовать слабый указатель, вы должны преобразовать его в QSharedPointer. Вы никогда не должны основывать решение на действии слабого указателя. Вы можете использовать только data() или isNull(), чтобы определить, что указатель нулевой.

Как правило, чтобы использовать слабый указатель, вы должны преобразовать его в общий указатель, поскольку такая операция гарантирует, что объект будет существовать до тех пор, пока вы его используете. Это эквивалентно "блокированию" объекта для доступа и является единственным правильным способом использования объекта, на который указывает слабый указатель.

QScopedPointer:
Это просто вспомогательный класс, который будет удалять указанный объект, когда указатель выйдет из области видимости. Таким образом, связывает динамически размещенный объект с переменной областью действия.

Вы можете использовать это для семантики RAII для локальных жителей, например:

MyClass *foo() {
    QScopedPointer<MyClass> myItem(new MyClass);
    // Some logic
    if (some condition) {
        return nullptr; // myItem will be deleted here
    }
    return myItem.take(); // Release item from scoped pointer and return it
}

Элемент также будет удален в случае исключения

Другим вариантом использования могут быть переменные-члены объекта. Тогда вам не нужно писать деструктор для них:

class MyClass {
public:
    MyClass() : myPtr(new int) {}
private:
    QScopedPointer<int> myPtr; // Will be deleted automatically when containing object is deleted
}