2015-11-03 4 views
4

Наконец, я установил Ubuntu и настроил Qt + Valgrind для предотвращения утечек памяти, которые я не мог сделать в Windows. Поэтому я не могу понять, обеспечивает ли этот код утечку памяти? На самом деле, Valgrind говорит, что у меня есть только 500 вопросов, но ничего о утечке. ЯПредоставляет ли этот код утечки памяти?

#include <QWidget> 
#include <QFrame> 
#include <QVBoxLayout> 
#include <QApplication> 

int main(int argc, char *argv[]) 

{ 
    QApplication a(argc, argv); 

    QWidget * wdgt = new QWidget; //this line should be the cause of leakage 
            //if it exist (as far as i know) 
    QVBoxLayout *layout = new QVBoxLayout; 
    QFrame * frame = new QFrame; 

    frame->setFrameStyle(QFrame::Panel | QFrame::Plain); 
    frame->setLineWidth(5); 
    layout->addWidget(frame); 

    wdgt->setLayout(layout); 
    wdgt->setFixedSize(800,600); 
    wdgt->show(); 

    return a.exec(); 
} 
+0

Нет, это не так, потому что ОС позаботится об этом. – 101010

+0

, но в этом случае доза не вводится 'int * a = new int;' – Mikhail

+5

Каждый 'новый' должен иметь соответствующий' delete'. В качестве альтернативы используйте интеллектуальные указатели –

ответ

8

Смотрите этот пост: Creating and deallocating a Qt widget object

Это explaines, что если один объект Qt имеет родителя, то он будет автоматически удален, когда родитель будет уничтожен.

В коде:

  • wdgt является родителем layout, потому что вы сделали wdgt->setLayout(layout).
  • wdgt является родителем frame, поскольку вы сделали layout->addWidget(frame) и layout родителем является wdgt. Как прокомментировал thuga, макет передал владение собственному родителю.

В вашем коде только wdgt является сиротой (без родителя Qt, чтобы удалить его автоматически).

Чтобы исправить это, вы можете либо дать ему родитель:

QWidget * wdgt = new QWidget(&app); 

Так что wdgt является потомком app, а затем будет удален автоматически при app разрушаются.

или удалить его самостоятельно:

int main(int argc, char *argv[]) 
{ 
    ... 
    int res = a.exec(); 
    delete wdgt; // this will delete wdgt, but also frame and layout 
    return res; 
} 

или fianlly, создать его как объект, так что он будет удален при выходе из области видимости:

int main(int argc, char *argv[]) 
{ 
    QApplication a(argc, argv); 

    QWidget wdgt; 

    QVBoxLayout *layout = new QVBoxLayout; 
    QFrame * frame = new QFrame; 

    frame->setFrameStyle(QFrame::Panel | QFrame::Plain); 
    frame->setLineWidth(5); 
    layout->addWidget(frame); 

    wdgt.setLayout(layout); 
    wdgt.setFixedSize(800,600); 
    wdgt.show(); 

    return a.exec(); 
} 

Кстати, заметим, что если вы делаете QVBoxLayout *layout = new QVBoxLayout(wdgt), нет необходимости делать wdgt->setLayout(layout).Так что те два куска кодов эквивалентен:

QVBoxLayout *layout = new QVBoxLayout(wdgt); // parenting upon construction 

так же, как:

QVBoxLayout *layout = new QVBoxLayout; // no parent 
wdgt->setLayout(layout); // reparenting 
+1

Самый чистый способ, который я считаю, - создать 'QWidget wdgt' в стеке! – Lol4t0

+0

Вы прокомментировали, когда я редактировал ;-) – jpo38

+0

На самом деле родителем как 'layout', так и' frame' будет 'wdgt'. Макеты не занимают владельцы виджетов, они просто передают собственность собственному родителям. – thuga

0

Да ваш код утечки памяти, потому что вы создаете объекты, используя new без использования управления памятью в Qt.

Перейти к

QApplication a(argc, argv); 
QWidget * wdgt = new QWidget(&app); 
QVBoxLayout *layout = new QVBoxLayout(wdgt); // optional, setLayout does that 
QFrame * frame = new QFrame(layout); // optional, addWidget does that 

использовать управление памятью в Qt.


В качестве альтернативы вы можете использовать C++ 11 общих указателей:

QApplication a(argc, argv); 
std::shared_ptr<QWidget> wdgt = std::make_shared<QWidget>(); 

QVBoxLayout *layout = new QVBoxLayout; 
QFrame * frame = new QFrame; 

Как только последний пользователь общий указатель выходит из области видимости, ваши объекты автоматически удаляются.

+0

Не злоупотребляйте общими указателями! – Lol4t0

+3

Требуется только 'QWidget (& app)'. Другие элементы являются родительскими ('QWidget :: setLayout' заставляет' QWidget' стать родителем 'QLayout' и' QLayout :: addWidget' делает 'QLayout' стать родителем' QWidget'). Только «wdgt» был Orpahn в OP. – jpo38

+1

А также виджеты автоматически воспроизводятся, когда вы добавляете их в макет и макеты при добавлении к виджетам и т. Д. – Lol4t0

0

Ваш код утечки памяти, но в первую очередь вы не должны писать код, где вы даже должны заботиться о утечка ресурсов. Пусть компилятор справится с этим для вас:

// main.cpp 
#include <QtWidgets> 

int main(int argc, char *argv[]) { 
    QApplication a(argc, argv); 
    QWidget widget; 
    QVBoxLayout layout(&widget); 
    QFrame frame; 

    frame.setFrameStyle(QFrame::Panel | QFrame::Plain); 
    frame.setLineWidth(5); 
    layout.addWidget(&frame); 

    widget.setFixedSize(800,600); 
    widget.show(); 
    return a.exec(); 
} 
+0

не может согласиться с вами. – Mikhail

+0

Я не уверен, но приведенные выше комментарии предполагают, что когда указатели передаются, они становятся собственниками и поэтому будут удалены. Это невозможно, если они находятся в стеке. Просьба уточнить –

+0

@EdHeal Это тоже работает, пока объекты создаются в правильном порядке. См. [Деревья объектов и собственность] (http://doc.qt.io/qt-5/objecttrees.html). – thuga

Смежные вопросы