Anonymous
Anonymous

Reputation: 4197

Container of Pointers vs Container of Objects - Performance

I was wondering if there is any difference in performance when you compare/contrast

A) Allocating objects on the heap, putting pointers to those objects in a container, operating on the container elsewhere in the code

Ex:

std::list<SomeObject*> someList;

// Somewhere else in the code
SomeObject* foo = new SomeObject(param1, param2);
someList.push_back(foo);

// Somewhere else in the code
while (itr != someList.end())
{
    (*itr)->DoStuff();
    //...
}

B) Creating an object, putting it in a container, operating on that container elsewhere in the code

Ex:

std::list<SomeObject> someList;

// Somewhere else in the code
SomeObject newObject(param1, param2);
someList.push_back(newObject);

// Somewhere else in the code
while (itr != someList.end())
{
    itr->DoStuff();
    ...
}

Assuming the pointers are all deallocated correctly and everything works fine, my question is...

If there is a difference, what would yield better performance, and how great would the difference be?

Upvotes: 1

Views: 3032

Answers (5)

stefanB
stefanB

Reputation: 79780

There is a performance hit when inserting objects instead of pointers to objects.

std::list as well as other std containers make a copy of the parameter that you store (for std::map both key and value is copied).

As your someList is a std::list the following line copies your object:

Foo foo;
someList.push_back(foo);           // copy foo object

It will get copied again when you retrieve it from list. So you are making of copies of the whole object compared to making copies of pointer when using:

Foo * foo = new Foo();
someList.push_back(foo);             // copy of foo*

You can double check by inserting print statements into Foo's constructor, destructor, copy constructor.

EDIT: As mentioned in comments, pop_front does not return anything. You usually get reference to front element with front then you pop_front to remove the element from list:

Foo * fooB = someList.front();    // copy of foo*
someList.pop_front();

OR

Foo fooB = someList.front();  // front() returns reference to element but if you
someList.pop_front();         // are going to pop it from list you need to keep a
                              // copy so Foo fooB = someList.front() makes a copy

Upvotes: 6

pmr
pmr

Reputation: 59811

Some additional things to consider (You have already been made aware of the copy semantics of STL containers):

  • Are your objects really smaller than pointers to them? This becomes more relevant if you use any kind of smart pointer as those have a tendency to be larger.
  • Copy operations are (often?) optimized to use memcpy() by the compiler. Especially this is probably not true for smart pointers.
  • Additional dereferencing caused by pointers

All the things I have mentioned are micro optimizations considerations and I'd discourage even thinking about them and go with them. On the other hand: A lot of my claims would need verification and would make for interesting test cases. Feel free to benchmark them.

Upvotes: 0

Murali VP
Murali VP

Reputation: 6417

With objects it is going to be memberwise copy (thus new object creation and copy of members) assuming there aren't any copy constructors and = operator overloads. Therefore, using pointers is efficient std::auto_ptr or boost's smart pointers better, but that is beyond the scope of this question.

If you still have to use object syntax using reference.

Upvotes: 0

Edan Maor
Edan Maor

Reputation: 10052

Like most performance questions, this doesn't have one clear cut answer.

For one thing, it depends on what exactly you're doing with the list. Pointers might make it easier to do various operations (like sorting). That's because comparing pointers and swapping pointers is probably going to be faster than comparing/swapping SomeObject (of course, it depends on the implementation of SomeObject).

On the other hand, dynamic memory allocation tends to be worse than allocating on the stack. So, assuming you have enough memory on the stack for all the objects, that's another thing to consider.

In the end, I would personally recommend the best piece of advice I've ever gotten: It's pointless trying to guess what will perform better. Code it the way that makes the most sense (easiest to implement/maintain). If, and only if* you later discover there is a performance problem, run a profiler and figure out why. Chances are, most programs won't need all these optimizations, and this will turn out to be a moot point.

Upvotes: 3

Marcin
Marcin

Reputation: 12590

It depends how you use the list. Do you just fill it with stuff, and do lookups, or do you insert and remove data regularly. Lookups may be marginally faster without pointers, while adding and removing elements will be faster with pointers.

Upvotes: 1

Related Questions