views:

202

answers:

5

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?

A: 

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.

Murali VP
You can't use std::auto_ptr in an STL container. The standard explicitly forbids it. Some compilers and implementations don't properly prevent the usage of auto_ptr in a container, but it is still a bad idea to use them that way even if the compiler allows it.
A. Levy
+1  A: 

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.

Marcin
+5  A: 

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
stefanB
You don't *need* to copy when you retrieve the value. Accessors return references (BTW you meant `front`, `pop_front` doesn't return anything.
UncleBens
+1: a very good answer.
NawaMan
I am not sure, really, of the quality of this answer. While it assesses the cost of working with copies of objects, it does not assess the specific cost introduced by working with pointers: a call to `new` may cost more than copying an object...
Matthieu M.
+3  A: 

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.

Edan Maor
Once you've managed to add something to a `std::list`, from there on I'd assume pointers to have worse performance. A linked list won't copy things any more, so there just remains the cost of extra indirection and extra allocation. The tradeoffs might be very different with other, non-node based containers: e.g sorting a vector of pointers = more expensive to compare (extra indirection) / less expensive to swap (if the class is larger and more complicated than pointer).
UncleBens
A: 

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.

pmr