2010-03-29 6 views
2

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

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

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

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

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

  4. для каждого цикла я пытаюсь использовать не работаю, я получил «тип указателя/массива, как ожидается, для этой операции вместо„Int“»

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

Спасибо за вашу помощь! Я новичок в 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; 
} 

ответ

1

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

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

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

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

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

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

EDIT:

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

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

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

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

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

+0

Спасибо! Еще один вопрос: метод экземпляра MyObject выглядит как MyObject (строка QString *, QObject * parent = 0). Когда я использую новый MyObject («Hello», this); Должен ли я иметь this-> setParent (parent) в методе экземпляра MyObject? Или родитель будет автоматически установлен? Если я использую setParent() в методе экземпляра, что произойдет, если я оставлю родительский пустой? Извините за все вопросы, но ваши ответы были очень полезными! – Martin

0

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

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

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

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

More info here

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

QList<MyObject*> list; 

Поэтому у вас есть одна менее возможная утечка памяти!

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

Редактировать:
3. Объекты MyObject имеют «это» в качестве родителей. Список не принимает права собственности на объекты, когда вы имеете дело с указателями.
4. Для цикла, возможно, вам стоит рассмотреть итераторы, посмотрите здесь qthelp://com.trolltech.qt.460/qdoc/qlist.html.

+0

Если я не использую указатель на свой список и просто использую список QList . Когда этот объект будет удален? Большое спасибо за вашу помощь! – Martin

+0

Ну, это зависит ... Если элементы списка имеют MyWidget как родительские, то они будут удалены, когда их родитель будет удален ... Если у них нет родителей, вам придется удалить их в деструкторе MyWidget. Помните, что когда вы имеете дело с указателями, все дело в том, «Кто владеет этим указателем?» ... Владелец имеет дело с удалением своих указателей ... –

+0

Но если я не использую указатель для списка как вы рекомендовали выше. Когда список будет удален? Объекты в списке, которые я понимаю, будут удалены в зависимости от их родителя. Но как насчет списка? – Martin

0

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

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

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

Все, это все.