Qt: правильно настроить мой собственный QWidget - PullRequest
2 голосов
/ 29 марта 2010

В Qt я пытаюсь настроить свой собственный QWidget, чтобы все работало хорошо из-за управления памятью и других вещей. Но я не могу понять, что все в порядке с указателями, кучей и стеком. У меня есть мой виджет MyWidget, который имеет QList с некоторыми объектами. Я не могу понять, как правильно все настроить.

Вы можете увидеть мой код ниже, и у меня есть несколько вопросов относительно этого:

  1. Список переменных instace создается в куче, было бы лучше создать его в стеке?

  2. В моем списке есть указатели, было бы лучше просто создать объект в стеке и добавить его в список? (Чтобы у меня вообще не было указателей в списке)

  3. Когда я добавлю объекты в список, они автоматически получат список в качестве родителя? Поэтому, когда я удаляю список, все объекты внутри списка будут удалены?

  4. Для каждого цикла, который я пытаюсь использовать, не работает, я получил "указатель / тип массива для этой операции вместо 'int'"

  5. В моем коде я хочу создать другие виджеты, которые берут объект из списка в качестве параметров. Это правильный способ сделать это, как у меня? Метод экземпляра MyOtherWidget выглядит следующим образом: MyOtherWidget (MyObject * myObject, QWidget * parent)

Спасибо за вашу помощь! Я новичок в Qt и C ++, поэтому было бы здорово, если бы вы могли направить меня в правильном направлении. Как я могу настроить это правильно, чтобы не было утечек памяти и использовать столько памяти, сколько необходимо. Как бы вы настроили то же самое?

Это мой код:

MyWidget.h:

class MyWidget : public QWidget
{
Q_OBJECT

public:
    MyWidget(QWidget *parent = 0);
    ~MyWidget();

private:
    QList<MyObject*> *list;
};

MyWidget.cpp:

MyWidget::MyWidget(QWidget *parent)
{
    ui.setupUi(this);

    list = new QList<MyObject*>();
    for (int i = 0; i<10; i++) 
    {
        MyObject *myObject = new MyObject("Hello",this);
        list->append(myObject);
    }

    foreach(MyObject *myObject, list)
    {
        //Lets say I want to create other widgets here and that they takes a MyObject as a parameter
        MyOtherWidget *myOtherWidget = new MyOtherWidget(myObject,this);
    }

}

MyWidget::~MyWidget(){
    delete list;
}

Ответы [ 3 ]

1 голос
/ 29 марта 2010

Ad.1. Время жизни списка должно совпадать с временем жизни экземпляра MyWidget, чтобы вы могли безопасно создавать список в стеке.

Ad.2. Вы можете сделать это, но класс MyObject должен иметь конструктор по умолчанию, конструктор копирования и оператор присваивания (подробности см. http://doc.trolltech.com/4.6/containers.html#container-classes).

Ad.3. Право собственности на объект не передается в приложение. Как и контейнеры STL, контейнеры Qt не вызывают delete для сохраненных указателей. Чтобы удалить все указатели, хранящиеся в QList (или другом контейнере Qt), вы можете использовать qDeleteAll (list). Имейте в виду, что вы, вероятно, не хотите делать это в коде, который вы разместили: вы передаете указатель MyWidget конструктору MyObject, и я предполагаю, что он затем используется в качестве родительского QObject. Поэтому все объекты QObject будут удалены при удалении MyWidget.

Ad.4. Второй аргумент макроса foreach должен быть контейнером, а не указателем на контейнер. Поэтому вы должны вызывать foreach (MyObject * obj, * list), если ваша переменная списка является указателем на QList.

Ad.5. Все будет в порядке, если MyOtherWidget не удаляет переданный MyObject (потому что MyWidget уже является родителем MyObject, и вы в конечном итоге удалите один и тот же объект дважды).

Это грубое упрощение, но вы должны попытаться написать свой код таким образом, чтобы вам вообще не нужно было вызывать delete. Создавайте вещи в стеке или используйте механизм Qt parent-children (то есть родители удаляют своих детей). Позже вы можете захотеть прочитать об умных указателях (QSharedPointer, QScopedPointer и т. Д.).

EDIT:

Будет ли установлен родитель MyObject или нет, зависит от того, что вы делаете в конструкторе MyObject. Если вы передаете родительский аргумент конструктору QObject, то есть ваш конструктор Myobject выглядит следующим образом:

MyObject(const QString &text, QObject *parent = 0) : QObject(parent)
{
// more code...
}

родитель будет установлен, потому что это будет сделано в конструкторе QObject, который будет вызываться из-за кода ": QObject (parent)". Что делать, если у вас нет этого фрагмента? Поскольку MyObject наследует QObject, и вы не указываете, какой конструктор следует называть конструктором QObject по умолчанию, то есть будет вызываться QObject (QObject * parent = 0), поэтому родительский элемент вашего MyObject будет иметь значение NULL и не будет Исключен.

Я бы старался избегать явной установки parent с помощью метода setParent - для базовых сценариев установки родительской функции в конструкторе должно быть достаточно.

Старайтесь использовать правильную терминологию (не «метод экземпляра», а «конструктор»), читайте документацию Qt, руководствуйтесь здравым смыслом и старайтесь не думать, что что-то будет сделано автоматически. Родитель не устанавливается «автоматически» только потому, что вы называете один аргумент «родительским» - он установлен, потому что есть фрагмент кода, который делает это в конструкторе QObject, и вы обязаны вызвать передачу соответствующего родителя конструктору QObject в классах которые наследуют QObject.

0 голосов
/ 30 марта 2010

Вам не нужно хранить дочерние виджеты в списке, если вы делаете их родителями текущего виджета. (Обычно вы создаете свои виджеты в стеке с новыми).

Qt имеет функцию автоочистки, которая означает, что, если виджет удаляется, все дочерние виджеты (виджеты, родительские элементы которых являются удаляемым виджетом) удаляются в.

Так что единственное, что вам нужно будет сделать (особенно для временных всплывающих виджетов), это стереть / удалить "всплывающее окно" виджета или как бы вы ни назвали свой всплывающий виджет.

Вот и все.

0 голосов
/ 29 марта 2010

Да, проблема в том, что вы удаляете объект списка, но не его элементы!

Предлагаю вам взглянуть на:

QList<Employee *> list;
list.append(new Employee("Blackpool", "Stephen"));
list.append(new Employee("Twist", "Oliver"));

qDeleteAll(list.begin(), list.end());
list.clear();

Подробнее здесь

Я бы также спросил, действительно ли вам нужен указатель на ваш список? Вы можете просто получить:

QList<MyObject*> list;

Таким образом, у вас меньше возможной утечки памяти!

Надеюсь, это немного поможет!

Редактировать:
3. Ваши объекты MyObject имеют "this" в качестве родителей. Список не принимает владение объектами, когда вы имеете дело с указателями.
4. Для цикла, возможно, вам следует рассмотреть Итераторы, посмотрите здесь

...