在 Qt 中,我正在尝试设置我自己的 QWidget,因此由于内存管理和其他原因,一切都应该运行良好。但我似乎无法完全理解指针、堆和堆栈。我有我的小部件 MyWidget,它有一个包含一些对象的 QList。我不知道如何正确设置一切。
您可以在下面看到我的代码,我对此有一些疑问:
-
instace 变量列表是在堆上创建的,在堆栈上创建它会更好吗?
-
在我的列表中,我有指针,在堆栈上创建对象并将其附加到列表中会更好吗? (所以我在列表中根本没有指针)
-
当我将对象追加到列表中时,它们会自动将该列表作为其父级吗?那么,当我删除列表时,列表中的所有对象都将被删除?
- 循环不起作用,我得到“此操作需要一个指针/数组类型,而不是‘int’”
-
在我的代码中,我想创建其他小部件,将列表中的对象作为参数。像我这样的做法正确吗? 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;
}
In Qt I'm trying to set up my own QWidget so everything should work good due to memory management and other things. But I can't seem to get it all right with pointers, heap and stack. I have my widget MyWidget that have a QList with some objects. I can't figure out how to set up everything right.
You can see my code below and I have some questions regarding this:
-
The instace variable list is created on the heap, would it be better to create it on the stack?
-
In my list I have pointers, would it be better to just create the object on the stack and append it to the list? (So that I don't have pointers in the list at all)
-
When I append the objects to the list will they get the list as their parent automatically? So when I delete the list all objects inside the list will be deleted?
-
The for each loop I'm trying to use isn't working, I got "a pointer/array type was expected for this operation instead of 'int'"
-
In my code I want to create other widgets that takes the object from the list as parameters. Is it the right way to do it like I have? MyOtherWidget's instance method looks like this: MyOtherWidget(MyObject *myObject, QWidget *parent)
Thanks for your help! I'm new to Qt and C++ so it would be great if you could guide me in the right direction. How can I setup this in the right way to make it easy, don't get memory leaks and use as little memory as needed. How would you setup the same thing?
This is my code:
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。列表的生命周期应该与 MyWidget 实例的生命周期相同,因此您可以安全地在堆栈上创建列表。
广告2。您可以这样做,但 MyObject 类需要有一个默认构造函数、一个复制构造函数和一个赋值运算符(请参阅 http://doc.trolltech.com/4.6/containers.html#container-classes 了解详细信息)。
广告.3。对象的所有权不会在追加时转移。就像 STL 容器一样,Qt 容器不会对存储的指针调用删除。要删除 QList(或其他 Qt 容器)中存储的所有指针,可以使用 qDeleteAll(list)。请注意,您可能不想在您发布的代码中这样做:您将 MyWidget 指针传递给 MyObject 构造函数,我假设它随后用作 QObject 父级。所以当MyWidget被删除时,所有的QObject都会被删除。
广告 4。 foreach 宏的第二个参数应该是一个容器,而不是指向容器的指针。因此,如果您的列表变量是指向 QList 的指针,您应该调用 foreach(MyObject *obj, *list)。
广告 5。只要 MyOtherWidget 不删除传递的 MyObject 就应该没问题(因为 MyWidget 已经是 MyObject 的父级,并且您最终会删除同一对象两次)。
这是一个粗略的简化,但您应该尝试以根本不需要调用删除的方式编写代码。在堆栈上创建内容或依赖 Qt 父子机制(即父级删除其子级)。稍后您可能想了解智能指针(QSharedPointer、QScopedPointer 等)。
编辑:
是否设置 MyObject 的父级取决于您在 MyObject 构造函数中所做的操作。如果您将父参数传递给 QObject 构造函数,即您的 Myobject 构造函数如下所示:
将设置父项,因为它将在 QObject 构造函数中完成,该构造函数将因“:QObject(parent)”代码而被调用。如果没有这个片段怎么办?由于MyObject继承了QObject,并且你没有指定应该调用哪个构造函数默认的QObject构造函数,即QObject(QObject *parent = 0)将被调用,所以你的MyObject的父级将为NULL并且不会被调用已删除。
我会尝试避免通过 setParent 方法显式设置父级 - 对于基本用例,在构造函数中设置父级应该足够了。
尝试使用正确的术语(不是“实例方法”,而是“构造函数”),阅读 Qt 文档,使用常识,并尽量不要认为任何事情都会自动完成。父级不会仅仅因为您调用一个参数“父级”而“自动”设置 - 它被设置,因为有一段代码在 QObject 构造函数中执行此操作,并且您有责任在类中调用将正确的父级传递给 QObject 构造函数继承QObject。
Ad.1. The lifetime of the list should be the same as the lifetime of the MyWidget instance, so you can safely create the list on the stack.
Ad.2. You could do that, but MyObject class would need to have a default constructor, a copy constructor, and an assignment operator (see http://doc.trolltech.com/4.6/containers.html#container-classes for details).
Ad.3. The ownership of the object is not transferred on append. Just like STL containers, Qt containers doesn't call delete on stored pointers. To delete all pointers stored in QList (or other Qt container) you can use qDeleteAll(list). Mind, that you probably don't want to do so in the code you posted: you pass MyWidget pointer to MyObject constructor and I assume it is then used as QObject parent. So all QObjects will be deleted when MyWidget is deleted.
Ad.4. The second argument of foreach macro should be a container, not pointer to container. So you should call foreach(MyObject *obj, *list) if your list variable is a pointer to QList.
Ad.5. You should be fine as long as MyOtherWidget doesn't delete the passed MyObject (because the MyWidget is already a parent of MyObject and you'd end up deleting the same object twice).
It's a gross simplification, but you should try to write your code in such way that you won't need to call delete at all. Create stuff on the stack or rely on Qt parent-children mechanism (i.e. parents delete their children). Later on you might want to read about smart pointers (QSharedPointer, QScopedPointer, etc.).
EDIT:
Whether the parent of MyObject is set or not depends on what you're doing in MyObject constructor. If you pass parent argument to QObject constructor, i.e. your Myobject constructor looks like this:
the parent will be set, because it will be done in QObject constructor, which will be called because of the ":QObject(parent)" code. What if you don't have this fragment? Since the MyObject inherits QObject, and you don't specify which constructor should be called the default QObject constructor, i.e. QObject(QObject *parent = 0) will be called, so the parent of your MyObject will be NULL and it won't be deleted.
I'd try to avoid setting parent explicitly through setParent method - for basic use cases setting parent in constructor should be enough.
Try to use correct terminology (not "instance method", but "constructor"), read Qt documentation, use common sense and try not to think that anything will be done automatically. The parent is not set "automatically" just because you call one argument "parent" - it is set, because there is a piece of code that does it in QObject constructor and it's your responsibility to call pass proper parent to QObject constructor in the classes that inherit QObject.
是的,问题是您要删除列表的对象而不是其元素!
我建议您查看:
更多信息
我还想问您是否真的需要指向您的列表的指针?您可以简单地有一个简单的方法:
因此您可以减少内存泄漏的可能性!
希望这有一点帮助!
编辑:
3. 您的 MyObject 对象将“this”作为父对象。当您处理指针时,列表不会获取对象所有权。
4.对于循环,也许你应该考虑迭代器,看看这里 qthelp://com.trolltech.qt.460/qdoc/qlist.html。
Yes, the problem is that you're deleting your list's object but not its elements !
I suggest you have a look at :
More info here
I would also ask if you really need a pointer to your list ? You could simply have a simple :
Therefore you have one less possible memory leak !
Hope this helps a bit !
Edit :
3. Your MyObject objects have "this" as parents. The list doesnt take the objects ownership when you deal with pointers.
4. For the loop, maybe you should consider Iterators, have a look here qthelp://com.trolltech.qt.460/qdoc/qlist.html.
您不需要将子窗口部件存储在列表中,只要将它们设为当前窗口部件的父级即可。 (通常您使用 new 在堆栈上创建小部件)。
Qt 有一个自动清理功能,这意味着,如果一个小部件被删除,所有子小部件(其父级是被删除的小部件的小部件)都会被删除。
因此,您唯一需要确保(特别是对于临时弹出窗口小部件)擦除/删除窗口小部件“弹出窗口”或无论如何调用弹出窗口小部件。
就这样,就这样了。
You don't need to store the child widgets within a list, as long as you make them parents of the current widget. (Usually you create your widgets on the stack with new).
Qt has a auto-cleanup function, which means, if a widget gets removed all child widgets (widgets whose parent is the widget that gets removed) get removed to.
So the only thing you will have to make sure (especially for temporary popup widgets) to erase/remove the Widget "popup" or however you call your popup widget.
That's it, that's all.