Oleg Vazhnev
Oleg Vazhnev

Reputation: 24067

Storing objects in vector: better to store the object or a pointer to it?

I have objects that I'm using throughout application lifetime: they are never destroyed. I'm storing them in vector:

declaration:
    std::vector<DoubleValue> bidDealIndexes;

construction:
    bidDealIndexes(Instrument::InstrumentsCount())

 usage:
    DoubleValue& v = bidDealIndexes[0];

Alternatively I can store pointers:

declaration:
    std::vector<DoubleValue*> bidDealIndexes;

construction:
    for (int i = 0; i < Instrument::InstrumentsCount(); i++) {
        bidDealIndexes.push_back(new DoubleValue());
    }

 usage:
    DoubleValue* v = bidDealIndexes[0];

The question is which is preferable? Should one (or both) of these options should be avoided?

Upvotes: 3

Views: 2018

Answers (5)

Chris Drew
Chris Drew

Reputation: 15334

In c++11, storing by value like you have done would definitely be preferred. In c++03, I would probably still prefer storing by value unless performance measurements showed it to be a problem.

In c++11 the vector<T>(N) constructor you are using was changed to use value initialization instead of making N copies.

Storing by value is simpler and will probably perform better in your case. If performance is a concern measure it and see.

Edit: I did some crude measurements comparing by-value, raw-pointers & unique_ptr and by-value came out top.

Upvotes: 0

Richard Hodges
Richard Hodges

Reputation: 69882

In practice, if your object is a POD and your vector is less than several thousand items long, you will get better performance by using a

std::vector<DoubleValue>

. Copies are very cheap compared to cache misses.

If DoubleValue is (very) big or noncopyable and the vector is also the controller of the object's lifetime, then use

std::vector<std::unique_ptr<DoubleValue>>

If DoubleValue is big and you would prefer by-value style (you should), then you could consider implementing DoubleValue using the pimpl idiom and making it copyable or moveable which would allow you to store it in a std::vector.

Upvotes: 2

Deduplicator
Deduplicator

Reputation: 45654

If your vector is constant-length, consider using std::array instead.
Otherwise, stick to a std::vector of element. You might want to call reserve() before storing the elements to avoid superfluous copying, if you have to insert a whole batch of elements.

For experts only: If the objects are expensive to move though, and managing the added members lifetime is somebody elses problem (e.g they stay alive until end of program), then you might consider storing pointers as an optimisation. Still, only consider that after careful measurement and consideration.

Upvotes: 0

Nathan
Nathan

Reputation: 4937

Storage by Value

Storing an object directly into a vector (or other STL container) is best left to primitive types when possible. This is because each insertion actually creates a copy of the object being stored. If you are storing a class object, such as your DoubleValue type, then the copy constructor is called each time you push_back. If the copy constructor is cheap (i.e. there is little storage inside the class and the copy constructor does little or no work), then storage by value will make your life simple. For more complex objects, storage by value may not even be possible. For example, iostreams cannot be copied, so they cannot be placed into a vector. For classes with expensive copy constructors, storage by value will slow down execution and increase memory footprint.

Summary: Use for lightweight objects

Storage by raw Pointer

With the advent of C++11 (and some other 3rd party libraries like boost), storage via raw pointer is discouraged due to the complications of tracking ownership and object lifetime. This is a whole other topic area that's been well covered in Stack Overflow. If you cannot use C++11, then take care when storing by raw pointer. This can be more performant than storage by value, and allows for storage of object types that cannot be copied (such as iostreams).

Summary: Use for heavyweight objects when smart pointers are not available

Storage by smart pointer

C++11 introduces smart pointers in the form of std::shared_ptr and their ilk. These manage the lifetime of the object through reference counting and follow the RAII (resource acquisition is initialization) pattern. The net-effect is that from your perspective they work like raw pointers but you don't have to worry about:

  1. pointers to deleted objects
  2. who is responsible for deleting the object

I don't know if shared_ptr is most appropriate in your situation, but the usage of smart pointers looks something like:

std::vector<std::shared_ptr<DoubleValue> > bigDealIndexes;
bigDealIndexes.push_back(std::shared_ptr<DoubleValue>(new DoubleValue));

std::cout << "Value of first big deal: " << *(bigDealIndexes[0]) << std::endl;
std::cout << "Member 'a':              " << bigDealIndexes[0]->a << std::endl;

Summary: Use for heavyweight objects when using C++11, boost, or a similar library

Upvotes: 2

Wojtek Surowka
Wojtek Surowka

Reputation: 20993

Objects are always preferred, and pointers should be avoided unless you need them. The main argument is that one should not complicate things without reason, and pointers introduce complication. In your example there is no need for pointers.

Upvotes: 2

Related Questions