When to use an object in a vector and when to use a pointer to an object in a vector?

When you create objects and save them in a vector. What are the pros and cons between these three and in which case should they be used?

An object:

std::vector<obj> collection;
collection.push_back(obj{});

      

Object pointer:

std::vector<obj*> collection;
collection.push_back(new obj{});

      

Smart Pointer:

std::vector<std::unique_ptr<obj>> collection;
collection.push_back(std::unique_ptr<obj>(new obj{}));

      

+3


source to share


5 answers


If the type of the object supports copying and assignment, you should eschew pointers, and place the object in a vector (and everywhere, except you, you probably shouldn't have pointers to such an object).



If the object type has personality and does not support copying and assignment (or only supports copy for implementing a clone

), then you will need to hold pointers into a vector. Whether smart pointers or raw pointers are used by a vector, and what is the policy regarding the lifetime of the object. In my experience, most of the time, vectors are used for navigation, in which case you should use the original pointers.

+3


source


  • The first approach is classic, objects will be destroyed at the end of the container's life. This may have the disadvantage of operations such as std::sort

    where a lot of movement is involved compared to a simple pointer (if that's a problem at all in the case of a particular object). Note that this may be the preferred approach with objects that support copy / assign.

  • The second approach can have additional speed (holding huge objects with poor copy / move performance in the container is always a bad idea), but has the disadvantage of dealing with freeing memory yourself if you don't want to keep those objects around after the container is destroyed.

  • The third approach is more or less fast than the second for sorting operations, plus it has the advantage of using a smart pointer that will automatically release memory when the container goes out of scope.



It really comes down to the estimated duration of the objects and how efficiently your objects can be copied. Do some profiling for your intended test case and don't decide "a priori" which one to use (as James points out, this could be a case of premature optimization).

+1


source


I personally would use the first option as much as possible, unless there is a good reason to use the other (the other two are almost equivalent, so there isn't much difference there).

The main reason is that the result is cleaner code, which is almost certainly better for RAII ( http://en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization ) because the compiler generates code that has no leaks. Some people here point to performance issues that are valid, but less common than most people think.

So the bottom line (IMHO) is this: go through the simplest and cleanest option unless there is a compelling reason to do so. Don't add unnecessary complexity to your application unless you absolutely have to. I've seen too many code errors due to premature optimizations that aren't even necessary in most cases.

+1


source


If your object is simple data, then the first option is always better. New memory is allocated and managed inside the vector object, so you don't need to worry about that.

0


source


  • Vector of objects. Useful for elements that are usually passed by value, easily copied.

  • The vector of source pointers. For more complex objects (that you don't want to copy), copy is efficient, but somewhere you have to manage the lifetime of those pointers. Even if you are deleting, when you are removing an element from a vector, you should be aware that there is not about it. This might be the best approach in cases where the life of the objects is managed elsewhere and you know these pointers will remain valid and you just want to cast them into a vector for some use, for example. An API that returns a subset of a larger collection can do so as a vector of pointers to those objects.

  • Typically used for this shared_ptr

    because the vector belongs to one copy and whoever fetches it for read / use gets another copy, so there is no lifespan issue. With unique_ptr it is pretty much the policy that it belongs to the vector, and the main reason for this (2) is not having to manually delete it when it is removed from the vector. The vector must be wrapped inside the class that controls it. Use shared_ptr

    here for years is the generally recommended design when you are not storing the objects themselves for general safety of life.

0


source







All Articles