Consequences of owning modeling with smart pointers

Currently, I manually manage the life cycle of objects in my project. I am considering switching to smart pointers, in particular tr1 :: shared_pointer and tr1 :: weak_ptr. Nevertheless, I see a couple of problems and would like to get some input into best practices.

Consider the following class diagram:

Polyhedron Class Diagram

In this diagram, thick arrows represent associations with property semantics (the source is responsible for deleting the target or goals). Thin arrows represent associations without ownership.

From what I understand, one way to implement associations with property semantics would be to use tr1 :: shared_ptr (or a collection of them). Other associations can be implemented using either tr1 :: shared_ptr or tr1 :: weak_ptr. The first is prohibited if this can lead to circular references, as this will prevent proper allocation of resources.

As you can see, there is a circle of associations between the Edge and Side classes. I can easily break this by implementing the "left" and "right" associations from Edge to Side using tr1 :: weak_ptrs. However, I would prefer to use smart pointers to document the semantics of property associations. Therefore, I would like to use shared_ptrs only for associations represented by thick arrows in the diagram, and weak_ptrs for everything else.

Now my first question is: should weak_ptrs be used liberally, as described above, or should I use them as little as possible (just to avoid circular references)?

The next question: suppose I have a function that calculates the average value of a set of vertices. Suppose further that I implemented the association from the polyhedron to its vertices as follows:

class Vertex; class Polyhedron { protected: std::vector<std::tr1::shared_ptr<Vertex> > m_vertices; }; 

and that I implemented an association from side to its tops, for example:

 class Vertex; class Side { protected: std::vector<std::tr1::weak_ptr<Vertex> > m_vertices; }; 

Note that the set of Side vertices is a subset of the set of vertices of a polyhedron. Now suppose I have a function that calculates the average of a set of vertices. Currently, the function is declared like this:

 const Vertex centerOfVertices(std::vector<Vertex*> vertices); 

Now, if I represent associations, as indicated above, I suddenly need two functions, if I understand everything correctly:

 const Vertex centerOfVertices(std::vector<std::tr1::shared_ptr<Vertex> > vertices); const Vertex centerOfVertices(std::vector<std::tr1::weak_ptr<Vertex> > vertices); 

Because I cannot convert the shared_ptr vector and weak_ptr vector. This is funny for me. I would like to know what approach I should take here to avoid this situation.

+4
source share
3 answers

However, I would prefer to use smart pointers to document the semantics of association associations in code.

As expected. What they express, after all.

Therefore, I would like to use shared_ptrs only for associations represented by thick arrows in the diagram, and weak_ptrs for everything else.

Go for this, with one caveat: your ownership does not look like co-ownership, simple, unique ownership. Therefore, the corresponding smart pointer here isnt shared_ptr , but rather std::unique_ptr , and weak pointers will then just be rude pointers.

Now, if I represent associations, as indicated above, I suddenly need two functions ...

Yes. Well, or you use templates.

Alternatively, since the function is not actually interested in sharing property rights, you can pass raw pointers to it, but this, of course, implies that you first get the original pointers from your structure, which requires an additional step for the client, which may not suitable for interface.

+1
source

Using generic pointers seems reasonable, especially since you may find that vertices, etc. can be shared between polyhedra.

To convert from a vector of weak pointers to a vector of generic pointers, use the explicit constructor:

 centerOfVertices(std::vector<std::tr1::shared_ptr<Vertex> >(vertices.begin(), vertices.end())); 
+1
source

You can also use shared_ptr for circular references. There are rare situations where this makes sense. However, you must take care to break the loop as soon as you are done with the objects.

0
source

All Articles