[완료] Qt에서의 메모리 할당/해제 메커니즘이 궁금합니다.

comkid의 이미지

질문이 좀 거창해졌는데요..

다른 것이 아니고 Qt Tutorial 4 - Let There Be Widgets 항목에 보면

 MyWidget::MyWidget(QWidget *parent)
     : QWidget(parent)
 {
     setFixedSize(200, 120);
 
     QPushButton *quit = new QPushButton(tr("Quit"), this);
     quit->setGeometry(62, 40, 75, 30);
     quit->setFont(QFont("Times", 18, QFont::Bold));
 
     connect(quit, SIGNAL(clicked()), qApp, SLOT(quit()));
 }

에서 quit에 대해 아래와 같이 설명이 나오는데요..

Quote:
Note that quit is a local variable in the constructor. MyWidget does not keep track of it; Qt does, and will automatically delete it when the MyWidget object is deleted. This is why MyWidget doesn't need a destructor. (On the other hand, there is no harm in deleting a child when you choose to. The child will automatically tell Qt about its imminent death.)

튜토리얼 볼 때는 스마트 포인터를 썼나 하고 그냥 그런가 보다 하고 넘어갔었는데요. 막상 제가 클래스 정의해서 하려니 정말 명시적으로 delete를 해주지 않아도 되는 것인가 하는 생각이 들어서요.

Qt의 메모리 할당/해제 메커니즘을 알면 답이 보일 것도 같은데 책이랑 문서랑도 봐도 (제가 키워드를 제대로 못 골라서인지) 제가 궁금한 부분에 대해서 알려주는 내용은 없어서요.

이런 고민을 하고 있는 이유는

QMainWindow를 상속받은 클래스를 정의하고 그 안에 제가 정의한 클래스(QObject를 상속받지 않은 C++ 클래스)에 대한 포인터를 멤버로 갖고 생성자에서 할당을 하려고 하는데 이런 경우에도 소멸자에 해제하는 루틴을 따로 만들지 않아도 알아서 해제가 되는 것인지..가 궁금해서요. 느낌 상(?) 그냥은 안될 것 같은데요. QObject를 상속한 클래스에 대해서만 자동으로 해제가 이루어지지 않나 막연히 추측하고 있는데..

저의 이런 궁금증을 속~ 시원하게 긁어 주실 분 안계신가요?

klara의 이미지

생각하신대로 일단은 QObject를 상속하지 않은 클래스는 자동 해제 대상에서 제외됩니다.
하지만 QObject를 상속받았으니까 무조건 자동 해제되는 건 아닙니다.
QObject를 상속받고, 부모 객체에 등록된 자식 객체가, 부모객체가 삭제될때 자동으로 삭제되는 것입니다.
여기서 말하는 부모는 상속관계에 있는 base 클래스와 derived 클래스를 말하는게 아니라 생성자에서 parent로 넘어간 포인터를 말합니다.
조금 더 자세한건 다음 글의 끝 부분에 적혀있습니다.
http://xylosper.net/112
디버깅 돌려보시면 소멸자에서 자식들을 해제하는 과정을 보실수도 있습니다.

comkid의 이미지

Colding Mice라는 샘플을 보면 QGraphicsItem에 대한 파생 클래스인 Mouse는 new로 생성할 때 따로 parent를 설정하지 않는데요. 이런 경우에는 어떤 식으로 해제가 되는 건가요?

     QGraphicsScene scene;
     scene.setSceneRect(-300, -300, 600, 600);
     scene.setItemIndexMethod(QGraphicsScene::NoIndex);
 
     for (int i = 0; i < MouseCount; ++i) {
         Mouse *mouse = new Mouse;
         mouse->setPos(::sin((i * 6.28) / MouseCount) * 200,
                       ::cos((i * 6.28) / MouseCount) * 200);
         scene.addItem(mouse);
     }

예제 간혹 보다보면 new로 동적할당 하면서도 parent를 넘기지 않는 애들이 있는데 이런 경우는 그 객체가 add되는 녀석이 해제를 하는게 아닐까 하고 넘어갔는데 실제로도 그러한지는 잘 모르겠어서요.

그리고 제가 Qt는 처음 써봐서 mignw-g++, qt, vim으로 MS 윈도우 환경에서 프로그래밍 하고 있는데요.
어떤 식으로 디버깅 해볼 수 있는지 참고 할 수 있는 자료도 알려주시면 감사하겠습니다..^^;

Have a good day!

klara의 이미지

이런 경우는 좀 특별한 경우입니다.
assistant를 보시면 알겠지만 애시당초 QGraphicsItem는 QObject를 상속받은 클래스가 아닙니다.
특별하게 설계된 아이템 클래스들은 add된 곳에서 삭제됩니다.
말씀하신대로 이경우는 각 아이템은 그 아이템이 등록된 부모 아이템이나 최종적으로는 scene이 삭제할 책임을 가집니다.
이외에도 QListWidget/QTableWidget/QTreeWidget과 그 item클래스들도 마찬가지로 최종적으로 각 widget에 의해서 할당된 item들이 해제됩니다.
이것들을 해제하는 알고리즘은 어려운게 아닙니다.
예를 들어 QGraphicsScene의 소멸자는 다음과 같이 간단합니다.

QGraphicsScene::~QGraphicsScene()
{
    Q_D(QGraphicsScene);
    for (int i = 0; i < d->newItems.size(); ++i) {
        if (QGraphicsItem *item = d->newItems[i]) {
            d->newItems[i] = 0;
            d->removeFromIndex(item);
            item->d_func()->scene = 0;
            delete item;
        }
    }
    for (int i = 0; i < d->allItems.size(); ++i) {
        if (QGraphicsItem *item = d->allItems[i]) {
            if (!d->removedItems.contains(item)) {
                d->allItems[i] = 0;
                d->removeFromIndex(item);
                item->d_func()->scene = 0;
                delete item;
            }
        }
    }
}

보통은 문서에 나와있습니다만, 실제로 삭제되는지 궁금하다면 디버깅을 돌려보거나 위와같이 소스코드를 직접 찾아보면 되겠죠.
디버깅에 대해선, 전 항상 kdevelop이나 eclipse같은 IDE로밖에 안해봐서 직접 gdb등을 이용한 디버깅은 잘 모르겠네요.
Qt라고 특별히 다를 건 없는 것 같습니다. 중단점 찍고 스택보거나 출력함수로 직접 출력해보거나...
참고로 직접 출력할때는 qDebug()를 이용하면 간편합니다.
comkid의 이미지

xylosper님 블로그도 갔었는데.. 링크해주신.. 부분은 왜 못 봤던 건지-_-;;

parent로 this가 넘어가는 걸 주의깊게 보질 않았었네요..

알려주신 내용으로 궁금한 부분은 해결되었습니다. 빠른 답변 감사합니다 :)

Have a good day!

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.