스마트 포인터는 C++표준 포인터의 모든 기능을 가지고 있으며 자동 가비지 컬렉션 기능을 제공하는 클래스이다. Qt로 프로그래밍할 때 메모리 관리 문제(메모리 관리 불량으로 인한 메모리 누수 및 버그)를 도와주는 스마트 포인터 클래스가 많이 있다. 그 중 몇 가지 핵심적인 클래스를 알아보자.
QSharedPointer 클래스는 외부 참조 카운트(즉, 개체 외부에 배치된 참조 카운터)를 통해 공유 포인터를 보유한다. C++의 std::shared_ptr
와 같다. constness 를 포함하여 일반적인 목적을 위해 일반 포인터와 똑같이 동작한다. 다른 QSharedPointer 객체가 참조하지 않는 한 범위를 벗어날 때 보유하고 있는 포인터를 삭제한다.
int *pI = new int;
QSharedPointer<int> pI1(pI);
QSharedPointer<int> pI2 = pI1;
pI1.clear();
// pI2는 여전히 pI를 가리키고 있으므로 삭제되지 않는다.
pI2.clear();
// 더 이상 공유하는 포인터가 없으므로 pI가 삭제된다.
QSharedPointer 및 QWeakPointer 는 재진입 클래스이다. 이것은 일반적으로 주어진 QSharedPointer 또는 QWeakPointer 객체가 동기화 없이 여러 스레드에서 동시에 액세스할 수 없음을 의미한다.
QScopedPointer 는 단순히 힙 할당 객체에 대한 포인터를 보유하고 소멸자에서 삭제한다. 따라서 현재 범위를 벗어날 때 가리키는 객체가 삭제되도록 보장한다.
MyClass *foo() {
QScopedPointer<MyClass> myItem(new MyClass);
// Some logic
if (some condition) {
return nullptr; // myItem은 여기서 삭제된다.
}
return myItem.take(); // 범위가 지정된 포인터에서 항목을 해제하고 반환한다.
}
이 클래스는 객체가 힙을 할당 및 삭제해야 하지만 더 이상은 필요하지 않을 때 유용하다. 다음 사례처럼 객체의 멤버 변수일 수 있다. 그런 다음 소멸자를 작성할 필요가 없다.
class MyClass {
public:
MyClass() : myPtr(new int) {}
private:
QScopedPointer<int> myPtr; // 포함된 개체가 삭제되면 자동으로 삭제된다.
}
QScopedPointer 는 가벼우며 추가 구조나 참조 카운팅을 사용하지 않는다.
QPointer 는 QObject 및 QObject 파생 클래스 인스턴스에 대한 보호된 포인터를 제공하는 템플릿 클래스다. 다른 누군가 소유한 QObject에 대한 포인터를 저장해야 할 때 유용하며 참조를 계속 보유하는 동안 파괴될 수 있다. 가리키는 객체가 파괴되면 자동으로 nullptr로 설정된다.
QObject *obj = new QObject;
QPointer<QObject> pObj(obj);
delete obj;
Q_ASSERT(pObj.isNull()); // pObj는 이제 nullptr이 된다.
외부 수단을 통해 개체가 삭제되지 않음을 보장할 수 있는 경우에만 QPointer를 사용하여 개체에 액세스할 수 있다.
공유 포인터에 대한 약한 참조를 보유할 수 있다. 개체가 파괴되는 것을 방지하지 않으며 단순히 재설정된다. std::weak_ptr
과 동일하며 lock()
은 toStrongRef()
와 동일하다. toStrongRef()
는 해당 참조를 보유하는 QSharedPointer 객체를 반환한다.
int *pI = new int;
QSharedPointer<int> pI1(pI);
QWeakPointer<int> pI2 = pI1;
pI1.clear();
// 더 이상 공유 포인터가 없으며 pI가 삭제된다.
//
// 참조 횟수를 증가시켜 삭제되지 않도록 한다.
QSharedPointer<int> pI2_locked = pI2.toStrongRef();
Q_ASSERT(pI2_locked.isNull());
QWeakPointer 개체는 QSharedPointer에서 할당을 통해서만 만들 수 있다. data()
또는 isNull()
을 사용하여 포인터가 nullptr인지 확인할 수 있다.