2009-09-17 15 views
11

Jestem bardzo zdezorientowany, jeśli chodzi o używanie destruktorów w Qt4 i mam nadzieję, że możecie mi pomóc.
Kiedy mam metody takie jak to (z „Des” to klasa):destruktory w Qt4

void Widget::create() { 
    Des *test = new Des; 
    test->show(); 
} 

jak mogę mieć pewność, że ten widget ma być usunięty po tym jak został zamknięty?

A w klasie "Des" mam to:

Des::Des() 
{ 
    QPushButton *push = new QPushButton("neu"); 
    QHBoxLayout *layout = new QHBoxLayout; 
    layout->addWidget(push); 
    setLayout(layout); 
} 

gdzie i jak mam usunąć * * Naciśnij i układ? co powinno znajdować się w destruktorze Des :: ~ Des()?

Odpowiedz

12

Inną opcją korzystania z deleteLater() lub rodziców, jest używanie funkcji usuwania przy zamknięciu dla widżetów. W takim przypadku Qt usunie widżet po zakończeniu jego wyświetlania.

Des *test = new Des; 
test->setAttribute(Qt::WA_DeleteOnClose); 
test->show(); 

Lubię używać go z drzewa obiektów Qt utrzymuje, tak aby ustawić usuwać na blisko do okna, a wszystkie widżety w oknie mieć odpowiednią rodzic określony, więc wszystkie one zostaną usunięte także.

+0

to wydaje się działać bardzo dobrze. dzięki. Kiedy jednak utworzę 4 nowe "testowe" -widgety i ponownie je zamknę, utworzenie kolejnego "testowego" -widgeta nie będzie kosztować więcej pamięci, ale aplikacja nadal zużywa tyle samo pamięci, co w przypadku 4-testowych -widgetów nadal by istniało. Czy to normalne? – Berschi

+1

@Berschi, możliwe, że albo Qt, albo twój system operacyjny, robi trochę optymalizacji pamięci.Jeśli piąty widżet, o którym wspomniałeś w swoim komentarzu, nie powoduje więcej pamięci, nie martwiłbym się zbytnio. Inną opcją, jeśli masz wątpliwości, jest znalezienie narzędzia takiego jak valgrind i uruchomienie programu. –

2

W większości przypadków należy tworzyć widgety na stosie:

QPushButton push("neu"); 

w ten sposób, że zostaną usunięte, gdy stają się one poza zakresem. Jeśli naprawdę chcesz je utworzyć na stercie, to Twoim obowiązkiem jest wywołać je, gdy nie są już potrzebne.

+1

Jest to nieco bardziej skomplikowane. QT wyzwoli zniszczenie niektórych obiektów w niektórych sytuacjach (jeśli są one zarejestrowane z rodzicem), a zatem posiadanie ich w stosie zabiłoby aplikację podwójnie za darmo. –

+3

dribeas, myślę, że po zniszczeniu obiektu QObject jest on automatycznie wyrejestrowywany z rodzica. – rpg

+1

Używam alokacji stosów z QObjects przez cały czas i działa dobrze. Dzięki za niedoinformowany downmod. –

3

This tutorial sugeruje, że nie trzeba jawnie usuwać widżetów, które zostały dodane do widżetów nadrzędnych. Mówi też, że nie zaszkodzi również je usunąć.

(nie testowałem tego, ale myślę, że tak długo, jak wyraźnie je usunąć przed widget rodzic zostanie usunięty, to powinno być OK.)

+2

+1, ale próba ich usunięcia, po usunięciu widżetu nadrzędnego kończy się dwukrotnym usunięciem i zgaśnięciem aplikacji. –

21

Qt wykorzystuje to, co nazywają object trees i jest to nieco inna z typowego podejścia RAII.

QObject klasa constructor przenosi wskaźnik do rodzica QObject. Kiedy ten rodzic QObject zostanie zniszczony, jego dzieci również zostaną zniszczone. Jest to dość powszechny wzorzec w klasach Qt, a zauważysz, że wielu konstruktorów akceptuje parametr *parent.

Jeśli spojrzysz na niektóre z Qt example programs zobaczysz, że faktycznie konstruują większość obiektów Qt na stercie i wykorzystują to drzewo obiektów do radzenia sobie z niszczeniem. Osobiście uważam, że ta strategia jest również przydatna, ponieważ obiekty GUI mogą mieć osobliwe czasy życia.

Qt nie zapewnia żadnych dodatkowych gwarancji poza standardowym C++, jeśli nie używasz QObject lub podklasy QObject (na przykład QWidget).


W tym konkretnym przypadku nie ma gwarancji, że coś zostanie usunięte.

Będziesz chciał coś takiego dla Des (zakładając Des jest podklasą QWidget):

class Des : public QWidget 
{ 
    Q_OBJECT 

public: 
    Des(QWidget* parent) 
    : QWidget(parent) 
    { 
     QPushButton* push = new QPushButton("neu"); 
     QHBoxLayout* layout = new QHBoxLayout(this); 
     layout->addWidget(push); // this re-parents push so layout 
           // is the parent of push 
     setLayout(layout); 
    } 

    ~Des() 
    { 
     // empty, since when Des is destroyed, all its children (in Qt terms) 
     // will be destroyed as well 
    } 
} 

I byłoby użyć klasy Des tak:

int someFunction() 
{ 
    // on the heap 
    Des* test = new Des(parent); // where parent is a QWidget* 
    test->show(); 
    ... 
    // test will be destroyed when its parent is destroyed 

    // or on the stack 
    Des foo(0); 
    foo.show(); 
    ... 
    // foo will fall out of scope and get deleted 
} 
+0

OK, jest to bardzo pomocne, ale mam jedno dodatkowe pytanie: Kiedy po prostu ZAMKNIĘTO ten widget nazywany "testem", nie oznacza to, że zostanie on również zniszczony, prawda? Muszę to zniszczyć/usunąć samemu. jak mam to zrobić? – Berschi

+2

Jeśli widget nie ma czystego życia i nie ma rodziców, z którymi można go skojarzyć, najlepszą opcją jest użycie funkcji usuwania przy zamknięciu, o której wspomina cjhuitt w innej odpowiedzi. – richardwb

+0

tylko po to, aby wyjaśnić, jeśli zmienimy element członkowski na "Pushbutton", musimy usunąć ręcznie przycisk w destruktorze widżetów lub zostanie on usunięty po usunięciu rodzica. – Naruto

5

odpowiedź Richardwb jest dobry - ale innym podejściem jest użycie slotu deleteLater, tak jak:

Des *test = new Des; 
test->show(); 
connect(test, SIGNAL(closed()), test, SLOT(deleteLater())); 

Oczywiście sygnał zamknięty() można zastąpić dowolnym sygnałem.

+0

nie ma sygnału SIGNAL (zamkniętego()) dla tego widgetu. SYGNAŁY są: customContextMenuRequested (QPoint), zniszczony() i zniszczony (QObject *) – Berschi

+0

OK, cóż, to było raczej ogólne pojęcie, niż konkretny przykład. Może możesz dodać sygnał, który zostanie wyemitowany, gdy twój obiekt zakończy pracę? Jest to przydatny wzorzec, pozwala tworzyć coś i zapominać o nim, pod warunkiem, że nie przechowujesz żadnych odniesień do niego i, że tak się stanie, w końcu się kończy. – Thomi

Powiązane problemy