Qt의 메모리 관리?


96

저는 Qt를 처음 접했고 메모리 관리와 객체의 수명에 대한 몇 가지 기본적인 사항이 궁금합니다. 개체를 언제 삭제 및 / 또는 파괴해야합니까? 자동으로 처리되는 것이 있습니까?

아래 예에서 내가 만든 개체 중 삭제해야하는 것은 무엇입니까? 인스턴스 변수 가 파괴 myOtherClass되면 어떻게됩니까 myClass? 객체를 전혀 삭제 (또는 파괴)하지 않으면 어떻게됩니까? 그게 기억에 문제가 될까요?

MyClass.h

class MyClass
{

public:
    MyClass();
    ~MyClass();
    MyOtherClass *myOtherClass;
};

MyClass.cpp

MyClass::MyClass() {
    myOtherClass = new MyOtherClass();

    MyOtherClass myOtherClass2;

    QString myString = "Hello";
}

보시다시피 이것은 매우 초보자에게 쉬운 일이지만 쉽게 배울 수있는 곳은 어디입니까?

답변:


100

QObjects 를 사용하여 고유 한 계층을 구축하는 경우 , 즉 새로 생성 된 모든 항목을 초기화합니다.QObject 된 모든를 부모로 .

QObject* parent = new QObject();
QObject* child = new QObject(parent);

다음은 충분하다 의 때문에deleteparentparent 의 소멸자가 파괴 처리됩니다 child. (시그널을 발행하여 수행하므로 child부모보다 먼저 수동으로 삭제해도 안전 합니다.)

먼저 자식을 삭제할 수도 있습니다. 순서는 중요하지 않습니다. 주문 이 수행 되는 예 중요한 여기 에 개체 트리에 대한 문서 입니다.

귀하의 MyClass 의 아이가 아닌 QObject, 당신은 일을하는 일반 C ++ 방법을 사용해야합니다.

또한 QObjects 의 부모-자식 계층 은 일반적으로 C ++ 클래스 계층 / 상속 트리의 계층과 독립적입니다. 즉, 할당 된 자식이 부모의 직접 하위 클래스 일 필요는 없습니다. . (하위 클래스) QObject이면 충분합니다.

그러나 다른 이유로 생성자에 의해 부과 된 제약이있을 수 있습니다. 예 를 들어 가시성 플래그와 그런 식으로 몇 가지 기본 레이아웃을 수행하기 때문에 QWidget(QWidget* parent=0)부모는 다른이어야합니다 QWidget. 그러나 일반적으로 Qt의 계층 구조 시스템의 QObject경우 부모로 사용할 수 있습니다 .


21
(It does this by issuing signals, so it is safe even when you delete child manually before the parent.)-> 이것이 안전한 이유가 아닙니다. Qt 4.7.4에서 QObject 자식은 직접 삭제됩니다 (를 통해 deleteqobject.cpp, 1955 행 참조). 자식 개체를 먼저 삭제하는 것이 안전한 이유는 QObject가 삭제 될 때 부모에게이를 잊어 버리도록 지시하기 때문입니다.
Martin Hennings

5
이것이 사실이 되려면 후손의 소멸자가 가상인지 확인해야합니다. 경우 ClassB의 상속 QObjectClassC에서 상속 ClassB다음은, ClassC단지 제대로 Qt의 부모 - 자식 관계에 의해 파괴 얻을 것이다 경우 ClassB의 소멸자는 가상이다.
Phlucious

1
대답의 링크는 이제 끊어졌습니다 (거의 4 년이 지나도 놀라운 일아닙니다 ...). 아마도이 qt-project.org/doc/qt-4.8/objecttrees.html 같은 것일까 요?
PeterSW

2
@Phlucious QObject의 소멸자는 이미 가상이므로 모든 하위 클래스의 소멸자를 자동으로 가상으로 만듭니다.
rubenvb

1
상속 트리의 한 클래스에 가상 소멸자가있는 경우 아래의 모든 하위 클래스에는 가상 소멸자가 있습니다. 이제 가상 소멸자가없는 가상 소멸자 체인 외부에 리프 부모 클래스가있는 경우 실제 개체가 해당 체인 아래에있을 때 특정 클래스에 대한 포인터를 삭제하면 문제가 발생할 수 있다고 생각합니다. QObject 하위 클래스의 경우 해당 하위 클래스의 인스턴스에 대한 QObject 포인터를 삭제하면 해당 하위 클래스의 소멸자 선언에서 가상 키워드를 잊어 버려도 문제가 없습니다.
rubenvb

47

Qt에서 소유권 개념이 매우 중요하다는 점을 지적함으로써 Debilski의 대답을 확장하고 싶습니다. 클래스 A가 클래스 B의 소유권을 가정하면 클래스 A가 삭제되면 클래스 B가 삭제됩니다. 개체를 만들고 상위를 지정할 때뿐만 아니라 한 개체가 다른 개체의 소유자가되는 여러 상황이 있습니다.

예를 들면 :

QVBoxLayout* layout = new QVBoxLayout;
QPushButton someButton = new QPushButton; // No owner specified.
layout->addWidget(someButton); // someButton still has no owner.
QWidget* widget = new QWidget;
widget->setLayout(layout); // someButton is "re-parented".
                           // widget now owns someButton.

다른 예시:

QMainWindow* window = new QMainWindow;
QWidget* widget = new QWidget; //widget has no owner
window->setCentralWidget(widget); //widget is now owned by window.

따라서 문서를 자주 확인하십시오. 일반적으로 메서드가 객체의 소유권에 영향을 미치는지 여부를 지정합니다.

Debilski에서 언급했듯이 이러한 규칙은 QObject에서 파생 된 객체에만 적용됩니다. 클래스가 QObject에서 파생되지 않으면 직접 파괴를 처리해야합니다.


쓰기의 차이점은 무엇입니까? QPushButton * someButton = new QPushButton (); 또는 QPushButton someButton = new QPushButton 또는 그냥 QPushButton someButton;
Martin

3
Ehh, QPushButton 사이에는 큰 차이가 있습니다. * someButton = new QPushButton; 및 QPushButton someButton ;. 전자는 힙에 객체를 할당하고 후자는 스택에 객체를 할당합니다. QPushButton에는 차이가 없습니다. * someButton = new QPushButton (); 그리고 QPushButton someButton = new QPushButton ;, 둘 다 객체의 기본 생성자를 호출합니다.
Austin

나는 이것에 대해 매우 새로워 서 물어서 미안하지만 "힙에 객체 할당"과 "스택에 할당"의 차이점은 무엇입니까? 힙은 언제 사용해야하고 스택은 언제 사용해야합니까? 감사!
Martin

3
동적 할당, 개체 범위 및 RAII에 대해 읽어야합니다. 일반 C ++의 경우 개체가 범위를 벗어나면 자동으로 소멸되므로 가능한 한 스택에 개체를 할당해야합니다. 클래스 멤버의 경우 성능 때문에 힙에 개체를 할당하는 것이 좋습니다. 그리고 객체가 함수 / 메소드의 실행보다 "오래"되기를 원할 때마다 객체를 힙에 할당해야합니다. 다시 말하지만 이것들은 약간의 읽기가 필요한 매우 중요한 주제입니다.
Austin

@Austin 성능을 위해 힙에 클래스 멤버를 할당해야한다는 일반적인 진술은 불록입니다. 그것은 정말로 다르며 성능에 문제가있을 때까지 자동 저장 기간이있는 변수를 선호해야합니다.
rubenvb

7

부모 (QObject 객체 또는 파생 클래스)에는 자식 (QObject / 파생 클래스)에 대한 포인터 목록이 있습니다. 부모가 파괴되는 동안 부모는 자식 목록의 모든 개체를 삭제합니다. QObject의이 속성을 사용하여 부모가 삭제 될 때마다 자식 개체가 자동으로 삭제되도록 할 수 있습니다. 다음 코드를 사용하여 관계를 설정할 수 있습니다.

QObject* parent = new QObject();
QObject* child = new QObject(parent);
delete parent;//all the child objects will get deleted when parent is deleted, child object which are deleted before the parent object is removed from the parent's child list so those destructor will not get called once again.

smartpointer를 사용하여 Qt에서 메모리를 관리하는 다른 방법이 있습니다. 다음 기사에서는 Qt의 다양한 스마트 포인터에 대해 설명합니다. https://blog.qt.digia.com/blog/2009/08/25/count-with-me-how-many-smart-pointer-classes-does-qt-have/


-2

이러한 답변에 추가하려면 검증을 위해 Visual Leak DetetorC ++를 기반으로하는 Qt 프로젝트를 포함하여 Visual C ++ 프로젝트에 라이브러리 를 활용하는 것이 좋습니다 .이 라이브러리는 new, delete, free and malloc문과 호환되며 잘 문서화되어 있고 사용하기 쉽습니다. 자신의 인터페이스 클래스 QDialog또는 QWidget상속 된 인터페이스 클래스를 만든 다음이 클래스의 새 개체를 만들 때 개체의 setAttribute(Qt::WA_DeleteOnClose)기능 을 실행하는 것을 잊지 마십시오 .

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.