views:

57

answers:

3

I need to insert pointers of classes (inherited from QObject) into a QList. I know that the following syntax can be used:

.h

QList<MyObject*> list;

.cpp

list.append(new MyObject("first", 1));
list.append(new MyObject("second", 2));
...

and then free memory:

if(!list.isEmpty())
{
    qDeleteAll(list);
    list.clear();
}

This should be valid and does not cause any memory leaks (as far as I know). However, I need to initialize objects before adding them to the collection. Can the following piece of code cause some errors like memory leaks or dangling pointers (I'll use the same way to delete pointers as above)?

MyObject *obj;

for(i = 0; i < 5; i++)
{   
    obj = new MyObject();
    if(!obj.Init(i, map.values(i)))
    {
        // handle error
    }
    else
    {
        list.append(obj);
    }
}

Thanks.

A: 

Use RAII (Resource Allocation Is Initialization). Initialize the object in constructor directly.

Then the code would look like:

for(i = 0; i < 5; i++)
{   
    list.append( new MyObject( i, map.values(i)));
    // In case of initialization failure, throw exception from the constructor
}
Cătălin Pitiș
what if exceptions are not allowed in his environment?
akira
... then another mechanism needs to be found for reporting errors. It might be something like a function "getLastError" (maybe thread safe). But why assuming exceptions not allowed? There is nothing mentioned in the question, so I kept it simple.
Cătălin Pitiș
Throwing an exception was in fact under my consideration. In case of initialization failure I want to receive an error message from the object for debugging purposes (currently using public method obj.getError()). I know that it is possible to report errors with exceptions (e.g. throwing a string), but currently I'm playing with return values and error messages (like Qt libraries) and I would like to stay on that path. That is the main reason why I asked if the latter code is fine.
Routa
And I would like to add that in some situations I need similar functionality on much more complex initializations and therefore putting everything under constructor does not seem to be very reasonable.
Routa
@Cătălin Pitiș: "other mechanism" .. yes, thats why i brought up the issue. since we do not know the motivation behind the code shown i would not introduce any other concepts and just answer the question. there are 1000 ways of initializing an object and 1000 reasons of why to pick one of the 1000 :)
akira
+2  A: 

if you take care of "obj" (the allocated but not initialized instance) in the "// handle error" case, your code is ok.

akira
A: 

You can use QScopedPointer..

From the Qt 4.6 documentation,

The QScopedPointer class stores a pointer to a dynamically allocated object, and deletes it upon destruction. Managing heap allocated objects manually is hard and error prone, with the common result that code leaks memory and is hard to maintain. QScopedPointer is a small utility class that heavily simplifies this by assigning stack-based memory ownership to heap allocations, more generally called resource acquisition is initialization(RAII).

Hope it helps..

Edit:

For example,

You will use,

QScopedPointer<QWidget> p(new QWidget());

instead of

QWidget *p = new QWidget();

and add the QScopedPointer into your QList without worrying about memory leak and dangling pointers.

liaK
so the inner loop looks like this: QScopedPointer<MyObject> obj(new MyObject()); if (obj->Init(map.values(i)) { list.append(obj.take()); } ... add that to answer to see the advantage.
akira
sorry I couldn't understand ur example. But just added a basic example from the docs to make things clear.. I dint add this before with the hope that people will anyway find it from the docs.. :)
liaK
which part of my essentially 3 line example is not clear? btw, your example will lead to a segfault, because the scoped ptr still OWNS the instance, thats why i used .take().
akira