Qt:以正确的方式设置我自己的QWidget

时间:2010-03-29 13:15:04

标签: qt memory-management qobject

在Qt中,我正在尝试建立自己的QWidget,因此一切都应该由于内存管理和其他事情而运行良好。但我似乎无法通过指针,堆和堆栈来完成任务。我的小部件MyWidget有一个带有一些对象的QList。我无法弄清楚如何正确设置一切。

您可以在下面看到我的代码,我对此有一些疑问:

  1. 在堆上创建instace变量列表,在堆栈上创建它会更好吗?

  2. 在我的列表中我有指针,是否最好只在堆栈上创建对象并将其附加到列表中? (所以我根本没有列表中的指针)

  3. 当我将对象追加到列表中时,他们会自动将列表作为父对象吗?那么当我删除列表时,列表中的所有对象都将被删除?

  4. 我正在尝试使用的每个循环都不起作用,我得到“这个操作需要一个指针/数组类型而不是'int'”

  5. 在我的代码中,我想创建其他小部件,将列表中的对象作为参数。这样做是否正确? MyOtherWidget的实例方法如下所示:MyOtherWidget(MyObject * myObject,QWidget * parent)

  6. 感谢您的帮助!我是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 个答案:

答案 0 :(得分:1)

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父级。因此,当删除MyWidget时,将删除所有QObject。

Ad.4。 foreach宏的第二个参数应该是一个容器,而不是指向容器的指针。因此,如果列表变量是指向QList的指针,则应调用foreach(MyObject * obj,* list)。

Ad.5。只要MyOtherWidget不删除传递的MyObject(因为MyWidget已经是MyObject的父节点,并且你最终会删除两次相同的对象),你应该没问题。

这是一个严格的简化,但您应该尝试编写代码,以便您根本不需要调用delete。在堆栈上创建东西或依赖Qt父子机制(即父母删除他们的孩子)。稍后您可能想要了解智能指针(QSharedPointer,QScopedPointer等)。

编辑:

是否设置了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方法显式设置父级 - 对于基本用例,在构造函数中设置父级应该就足够了。

尝试使用正确的术语(不是“实例方法”,但“构造函数”),阅读Qt文档,使用常识并尽量不要认为任何事情都会自动完成。父进程不是“自动”设置的,因为你调用了一个参数“parent” - 它被设置,因为有一段代码在QObject构造函数中执行它,你有责任在类中调用传递适当的父代到QObject构造函数继承QObject。

答案 1 :(得分: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对象具有“this”作为父项。处理指针时,列表不会占用对象所有权 4.对于循环,也许你应该考虑迭代器,看看qthelp://com.trolltech.qt.460/qdoc/qlist.html

答案 2 :(得分:0)

您不需要将子窗口小部件存储在列表中,只要您将它们设置为当前窗口小部件的父窗口即可。 (通常用新的方法在堆栈上创建小部件。)

Qt有一个自动清理功能,这意味着,如果一个小部件被删除,所有子窗口小部件(其父窗口被移除的窗口小部件的窗口小部件)都会被删除。

因此,您必须确保(特别是对于临时弹出窗口小部件)擦除/删除窗口小部件“弹出窗口”或者您调用弹出窗口小部件。

就是这样,就是这样。