For a long time I was using std::vector
and std::shared_ptr
hand in hand. Recently I started using std::shared_ptr<const T>
whenever a pointer to a const object was needed. This is all OK, since std::shared_ptr<T>
can be cast to std::shared_ptr<const T>
and then they share the same reference counter and everything feels natural.
But when I try to use constructs such as std::vector< std::shared_ptr<const T> >
I run into troubles. To simplify I will denote the two structures:
template <class T> using SharedPtrVector = std::vector< std::shared_ptr<T> >; template <class T> using SharedConstPtrVector = std::vector< std::shared_ptr<const T> >;
The problem is that although SharedPtrVector
and SharedConstPtrVector
are very similar, SharedConstPtrVector
cannot be cast to SharedPtrVector
.
So each time I want to be a const correct and write a function such as:
void f(const SharedConstPtrVector<T>& vec);
there is no way I can pass const SharedPtrVector<T>
to f
.
I was thinking about this a lot and considered several alternatives:
Write conversion functions
template <typename T> SharedConstPtrVector<T> toConst(const SharedPtrVector<T>&);
Write code in generic form:
template <typename T> void f(const std::vector< std::shared_ptr<T> >& vec);
or
template <typename TIterator> void f(TIterator begin, TIterator end);
Abandon the idea of std::vector< std::shared_ptr<const T> >
The problem with 1. is the computational overhead and increased uglyness of code, while 2. gives the code an "everything is a template" flavor.
I am an inexperienced programmer and I don't want to set out in the wrong direction. I would like to hear advice from someone who has experience with this problem.
The smart pointer has an internal counter which is decreased each time that a std::shared_ptr , pointing to the same resource, goes out of scope – this technique is called reference counting. When the last shared pointer is destroyed, the counter goes to zero, and the memory is deallocated.
The shared_ptr type is a smart pointer in the C++ standard library that is designed for scenarios in which more than one owner might have to manage the lifetime of the object in memory.
If your C++ implementation supports C++11 (or at least the C++11 shared_ptr ), then std::shared_ptr will be defined in <memory> . If your C++ implementation supports the C++ TR1 library extensions, then std::tr1::shared_ptr will likely be in <memory> (Microsoft Visual C++) or <tr1/memory> (g++'s libstdc++).
In general, C++ is a language that expects a programmer to have full control of used resources and objects' lifecycles. Shared pointers make the application's memory model more complex and couplings between its parts are hard to track. Thus, the whole application becomes more bug-prone.
I would suggest reviewing your design with a view to establish a clear owner of those object. This is the absence of clear ownership that lead people to use shared smart pointers.
Bjarne Stroustrup recommends using smart pointers only as a last resort. His recommendations (best to worst) are:
See Bjarne Stroustrup - The Essence of C++: With Examples in C++84, C++98, C++11, and C++14 at 0:37:40.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With