Why is using a pointer vector considered bad?

I recently met with the opinion that I should not use a pointer vector. I wanted to know - why can't I?

For example, if I have a class foo , this can be done:

 vector <foo*> v; v.push_back(new foo()); 

I have already seen some people vote for such practices, why?

+8
c ++ pointers vector std
source share
6 answers

Storing simple pointers in a container can lead to memory leaks and dangling pointers. Storing a pointer in a container does not define any ownership of the pointer. Thus, the container does not know the semantics of the operations of description and copying. When elements are removed from the container, the container does not know how to destroy them correctly, when the copy operation is performed, no copyright holders are known. Of course, you can always deal with these things yourself, but then a chance of human error is possible.

The use of smart pointers leaves the semantics of ownership and destruction up to them.

Another thing worth mentioning is that containers are divided into non-intrusive and intrusive contajers - they store the actual object provided instead of a copy, so it actually comes down to a collection of pointers. Non-intrusive pointers have some advantages, so you cannot generalize that pointers in a container are something that should be avoided at any time, but is recommended in most cases.

+10
source share

Using a raw pointer vector is not necessarily a bad style, if you remember that pointers do not have property semantics. When you start using new and delete , it usually means that you are doing something wrong.

In particular, the only cases where you should use new or delete in modern C ++ code is to build unique_ptr or create shared_ptr with user deletions.

For example, suppose we have a class that implements a bidirectional Graph , a Graph contains a number of Vertexes .

 class Vertex { public: Vertex(); // raw pointer. No ownership std::vector<Vertex *> edges; } class Graph { public: Graph() {}; void addNode() { vertexes.push_back(new Vertex); // in C++14: prefer std::make_unique<> } // not shown: our Graph class implements a method to traverse over it nodes private: // unique_ptr. Explicit ownership std::vector<std::unique_ptr<Vertex>> vertexes; } void connect(Vertex *a, Vertex *b) { a->edges.push_back(b); b->edges.push_back(a); } 

Notice how I have a raw Vertex * vector in this Vertex class? I can do this because the Vertexes lifetime it points to is controlled by the Graph class. Owning my Vertex class is explicit, just by looking at the code.

Another answer involves using shared_ptr. I personally do not like this approach, because general pointers, in general, make it very difficult to talk about the life of objects. In this particular example, generic pointers would not work at all due to circular references between Vertexes .

+11
source share

Since the vector destructor will not call delete on pointers, so this is an easy accidental memory leak. The destructor vector calls the destructors of all elements of the vector, but the original pointers do not have destructors.

However, you can use the smart pointer vector to ensure that destroying the vector will free the objects in it. vector<unique_ptr<foo>> can be used in C ++ 11, and in C ++ 98 with TR1 you can use vector<tr1::shared_ptr<foo>> (although shared_ptr has a little overhead compared to a raw pointer or unique_ptr )

Boost also has a library of pointer containers , where special delete behavior on destruction is built into the container itself, so you don't need smart pointers.

+8
source share

One issue is security exception .

For example, suppose an exception is thrown somewhere: in this case, the destructor std::vector called. But this call to the destructor does not remove the raw ownership pointers stored in the vector. Thus, the resources managed by these pointers are leaking out (these may be memory resources, so you have a memory leak, but they can also be memoryless resources, such as sockets, OpenGL textures, etc.).

Instead, if you have a smart pointer vector (for example, std::vector<std::unique_ptr<Foo>> ), then if a vector destructor is called, each selected element (safely belonging to a smart pointer) in the vector is deleted correctly, calling its destructor. Thus, the resources associated with each element (β€œsmart” specified in the vector) are properly released.

Please note that the observation vectors of raw pointers are accurate (assuming that the lifetime of the observed elements exceeds the waiting time of the vector). The problem is pointers owning .

+5
source share

I will talk specifically about the pointer vector, which is responsible for managing the lifetime of these objects, because this is the only case where the pointer vector is clearly an dubious choice.

There are much better alternatives. In particular:

 std::vector<std::shared_ptr<foo>> v; 

and

 std::vector<std::unique_ptr<foo>> v; 

and

 boost::ptr_vector<foo> v; // www.boost.org 

The above versions tell the user how they care about the lifetime of objects. Instead, using raw pointers can delete pointers more or less than once, especially if the code changes over time or exceptions occur.

If you use an interface such as "shared_ptr" or "unique_ptr", this will automatically document the life cycle management for the user. When you use raw pointers, you should clearly document how you manage the life cycle of objects, and hope that the right people read the documentation at the right time.

The advantages of using raw pointer vectors are that you have more flexibility in managing your life cycle and that you can get rid of some performance and space constraints.

+4
source share

Absolutely no problem when using a vector of pointers. Most of them offer smart pointers, but I just have to say that there is no problem using a vector of pointers without smart pointers. I do this all the time.

I agree with juanchopanza that the problem in your example is pointers derived from the new foo (). In a normal, well-grounded use case, you can have objects in some other C collection so that the objects are automatically destroyed when C is destroyed. Then, by doing in-depth operations on objects in C, you can create any number of other collections containing pointers to objects in C C. (If other collections used copies of objects that were wasteful of time and memory, while reference collections are strictly forbidden.) In this case, we never want to destroy any e objects in the collection of signs destroyed.

0
source share

All Articles