mpen
mpen

Reputation: 282825

Storing a List of Objects

Let's say I have a generic Object class, and a generic List class. I want to maintain a list of these Objects. Should I store them as List<Object> or List<Object*>?

If I use List<Object> and I have a method like:

if(some_condition) {
    Object obj;
    myObjectList.append(obj);
}

And my list class only keeps a reference to the object, so as soon as that if statement terminates, the object is destroyed, and the object I pushed becomes invalid. So then I end up doing something like:

Object *obj = new Object;
myObjectList.append(*obj);

So that it doesn't get destroyed. But now the objects are undeletable, no? Because now they're stored safely in the List as Objects, not pointers to Objects, so I can't call delete on them... or will they automatically be destroyed when they're popped from the list?

In that case, I should probably use List<Object*> and delete them from the list when I'm done with them, no?

So confused... I'm sure I have a fundamental misunderstanding here somewhere.

Upvotes: 5

Views: 13062

Answers (5)

Evan Teran
Evan Teran

Reputation: 90422

EDIT: As mentioned in a comment boost::ptr_list is even better since it is more efficient and has the same net effect as a std::list<boost::shared_ptr<T> >.


EDIT: You mention that you are using Qt in your comment. If you are using >= 4.5 you can use Qt's QList and QSharedPointer classes like this:

QList<QSharedPointer<Object> > object_list;
object_list.push_back(QSharedPointer<Object>(new Object));

I would recommend you use std::list<>. You also likely just want to store pointers to the objects so they aren't being copied all of the time.

So bottom line is:

Let's say you have a class named Object. You should do this:

std::list<boost::shared_ptr<Object> > object_list;
object_list.push_back(new Object);

For c++11/14, no need for boost, just use the standard smart pointers:

std::list<std::shared_ptr<Object>> object_list;
object_list.push_back(std::make_shared<Object>());

By using shared pointers, the objects will get cleaned up automatically when they are removed from the list (if there are no other shared_ptrS also pointing to it).

You could have a list<Object *>. But given your experience level, I feel that a reference counted pointer would be much easier for you to work with.

In that case, I should probably use List and delete them from the list when I'm done with them, no?

Yes, this is a viable option, but I highly recommend smart pointers to avoid the "...and delete them from the list..." step entirely.


NOTE:

also the example code you gave:

Object *obj = new Object;
myObjectList.append(*obj);

is probably not what you wanted, this makes a new object on the heap, they puts a copy of that in the list. If there is no delete obj after that, then you have a memory leak since raw pointers are not automatically deleted.

Upvotes: 5

user143506
user143506

Reputation: 1473

as with "all" things there is no one answer - the devil's in the details of what you want to do, or what your constraints are.

If the objects are lightweight and do not involve deep copying it's going to be more efficient to store the little things as copies. Otherwise, the overhead of smartish pointers is more than is warranted. If you are polymorPHic then you could use templated lists.

if it's more important to minimize copying, and eliminate redundant code from template instantiations, then use a list of smart, shared pointers.

Or use a list of naked pointers, use new/delete, and be meticulous with your pointer ownership.

Any list will act like a list, so the choice of list implementation is dependent on factors you aren't enumerating here.

Upvotes: 2

nonpolynomial237
nonpolynomial237

Reputation: 2169

You could use List, and then when it's time to deallocate an object at position x, you would use something like

void erase_object(list* l, int i) {
    delete (*list)[x]
    list -> removeObj((*list)[x]);
}

Upvotes: 1

Eugene
Eugene

Reputation: 7258

Use pointers, as was suggested. You are using "generic" objects, probably a base class, and list will actually contain some derived objects casted to base -- this means you must pass pointer to originally created object. Otherwise you will cull all the polymorfism out.

That is

class Base 
{ 
public:
    int x; 
    virtual int getData() const { return x; }
};
class Derived : public Base 
{ 
public:
    int y; 
    virtual int getData() const { return y; }
};

Derived obj1;
obj1.x = 1;
obj1.y = 2;

Base obj2 = obj1;
cout << obj2.getData();

This will print 1, since obj2 is just a copy of Base portion of obj1 and is really an instance of Base.

Upvotes: 1

stribika
stribika

Reputation: 3176

In the first case the Object is copied and only the original is destroyed. The other instance is kept in the list.

In the second version you can use the List destructor to delete the stored objects.

Upvotes: 3

Related Questions