I've been thinking about using shared pointers, and I know how to implement one myself--Don't want to do it, so I'm trying std::tr1::shared_ptr,and I have couple of questions...
How is the reference counting implemented? Does it use a doubly linked list? (Btw, I've already googled, but I can't find anything reliable.)
Are there any pitfalls for using the std::tr1::shared_ptr?
shared_ptr must manage a reference counter and the carrying of a deleter functor that is deduced by the type of the object given at initialization.
The shared_ptr class typically hosts two members: a T* (that is returned by operator-> and dereferenced in operator*) and a aux* where aux is a inner abstract class that contains:
a counter (incremented / decremented upon copy-assign / destroy)
whatever is needed to make increment / decrement atomic (not needed if specific platform atomic INC/DEC is available)
an abstract virtual destroy()=0;
a virtual destructor.
Such aux class (the actual name depends on the implementation) is derived by a family of templatized classes (parametrized on the type given by the explicit constructor, say U derived from T), that add:
a pointer to the object (same as T*, but with the actual type: this is needed to properly manage all the cases of T being a base for whatever U having multiple T in the derivation hierarchy)
a copy of the deletor object given as deletion policy to the explicit constructor (or the default deletor just doing delete p, where p is the U* above)
the override of the destroy method, calling the deleter functor.
A simplified sketch can be this one:
template<class T>
class shared_ptr
{
struct aux
{
unsigned count;
aux() :count(1) {}
virtual void destroy()=0;
virtual ~aux() {} //must be polymorphic
};
template<class U, class Deleter>
struct auximpl: public aux
{
U* p;
Deleter d;
auximpl(U* pu, Deleter x) :p(pu), d(x) {}
virtual void destroy() { d(p); }
};
template<class U>
struct default_deleter
{
void operator()(U* p) const { delete p; }
};
aux* pa;
T* pt;
void inc() { if(pa) interlocked_inc(pa->count); }
void dec()
{
if(pa && !interlocked_dec(pa->count))
{ pa->destroy(); delete pa; }
}
public:
shared_ptr() :pa(), pt() {}
template<class U, class Deleter>
shared_ptr(U* pu, Deleter d) :pa(new auximpl<U,Deleter>(pu,d)), pt(pu) {}
template<class U>
explicit shared_ptr(U* pu) :pa(new auximpl<U,default_deleter<U> >(pu,default_deleter<U>())), pt(pu) {}
shared_ptr(const shared_ptr& s) :pa(s.pa), pt(s.pt) { inc(); }
template<class U>
shared_ptr(const shared_ptr<U>& s) :pa(s.pa), pt(s.pt) { inc(); }
~shared_ptr() { dec(); }
shared_ptr& operator=(const shared_ptr& s)
{
if(this!=&s)
{
dec();
pa = s.pa; pt=s.pt;
inc();
}
return *this;
}
T* operator->() const { return pt; }
T& operator*() const { return *pt; }
};
Where weak_ptr interoperability is required a second counter (weak_count) is required in aux (will be incremented / decremented by weak_ptr), and delete pa must happen only when both the counters reach zero.
How is the reference counting implemented?
A smart pointer implementation could be deconstructed, using policy-based class design1, into :
Storage Policy
Ownership Policy
Conversion Policy
Checking Policy
included as template parameters.
Popular ownership strategies include: deep copy, reference counting, reference linking, and destructive copy.
Reference counting tracks the number of smart pointers pointing to (owning2) the same object. When the number goes to zero, the pointee object is deleted3. The actual counter could be:
Shared among smart pointer objects, where each smart pointer holds a pointer to the reference counter:
Included only in an additional structure that adds an extra level of indirection the pointee object. Here the space overhead of holding a counter in each smart pointer is exchanged with slower access speed:
Contained within the pointee object itself: intrusive reference counting. The disadvantage is that the object must be constructed a priori with facilities for counting:
Finally the method in your question, reference counting using doubly linked lists is called reference linking and it:
...[1] relies on the observation that you don't really need the actual count of smart pointer objects pointing to one pointee object; you only need to detect when that count goes down to zero. This leads to the idea of keeping an "ownership list" :
The advantage of reference linking over reference counting is that the former does not use extra free store, which makes it more reliable: Creating a reference-linked smart pointer cannot fail. The disadvantage is
that reference linking needs more memory for its bookkeeping (three pointers versus only one pointer plus one integer). Also, reference counting should be a bit speedier—when you copy smart pointers, only an indirection and an increment are needed. The list management is slightly more elaborate. In conclusion,
you should use reference linking only when the free store is scarce. Otherwise, prefer reference counting.
Regarding your second question:
Does it (std::shared_ptr) use a doubly linked list?
All that I could find in the C++ standard was:
20.7.2.2.6 shared_ptr creation
...
7. [ Note: These functions will typically allocate more memory than sizeof(T) to allow for internal bookkeeping structures such as the reference counts. —end note ]
Which, in my opinion, excludes doubly linked lists, as they do not contain actual count.
Your third question:
Are there any pitfalls for using the std::shared_ptr?
Reference management either counting or linking is a victim of the resource leak known as cyclic reference. Let's have an object A that holds a smart pointer to an object B. Also, object B holds a smart pointer to A. These two objects form a cyclic reference; even though you don't use any of them any more, they use each other. The reference management strategy cannot detect such cyclic references, and the two objects remain allocated forever.
Because the implementation of shared_ptr uses reference counting, cyclic references are potentially a problem. A cyclic shared_ptr chain can be broken by changing the code so that one of the references is a weak_ptr. This is done by assigning values between shared pointers and weak pointers, but a weak pointer doesn't affect the reference count. If the only pointers that point to an object are weak, the object is destroyed.
1. Each design feature with multiple implementations if formulated as policy.
2. Smart pointers similarly to pointers that point to object allocated with new, not only point to that object but also are responsible for its destruction and with the release of the memory it occupies.
3. With no further problems, if no other raw pointers are used and/or point to it.
[1] Modern C++ Design: Generic Programming and Design Patterns Applied. Andrei Alexandrescu, February 01, 2001
If you want to see all the gory details, you can have a look at the boost shared_ptr implementation:
https://github.com/boostorg/smart_ptr
The reference counting seems to usually be implemented with a counter and platform specific atomic increment/decrement instructions or explicit locking with a mutex (see the atomic_count_*.hpp files in the detail namespace).
Are there any pitfalls for using the std::tr1::shared_ptr?
Yes, If you create cycles in your shared memory pointers, then the memory being managed by the smart pointer will not be recycled when the last pointer goes out of scope because there are still references to the pointer (i.e., the cycles cause the reference count to not go down to zero).
For instance:
struct A
{
std::shared_ptr<A> ptr;
};
std::shared_ptr<A> shrd_ptr_1 = std::make_shared(A());
std::shared_ptr<B> shrd_ptr_2 = std::make_shared(A());
shrd_ptr_1->ptr = shrd_ptr_2;
shrd_ptr_2->ptr = shrd_ptr_1;
Now, even if shrd_ptr_1 and shrd_ptr_2 go out of scope, the memory they are managing is not reclaimed because the ptr member of each are pointing to each other. While this is a very naive example of such a memory cycle, it can, if you use these types of pointers without any discipline, occur in a much more nefarious and hard-to-track fashion. For instance, I could see where trying to implement a circular linked-list where each next pointer is a std::shared_ptr, if you're not too careful, could result in problems.
Related
Currently I'm using some functions from the glib library. With glib also comes the gio. glib is a C library and therefore I need to delete some structures that I create.
for many of the objects I create a smartpointer eg:
std::shared_ptr<GAsyncQueue> my_queue = std::shared_ptr<GAsyncQueue>(g_async_queue_create(), g_async_queue_unref);
For this creates a shared pointer to an GAsyncQueue and this is safely destroys the queue on its end of its life.
However, I encounter a problem when I obtain a pointer from the gio library that I should not free. In the following code my_connection is a GSocketClient which implements (in glib speak) GIOStream.
std::shared_ptr<GInputStream> my_input_stream =
std::shared_ptr<GInputStream> (
g_io_stream_get_input_stream(G_IO_STREAM(my_connection.get()))
);
Because the documentation on GIOStream mentions, that the pointer obtained with g_io_stream_get_input_stream() should not be freed. That is because it is owned by the my_connection instance.
I thought about creating a lamda for the destroy object, the second parameter of a shared pointer object. eg auto deleter = [](GInputStream* ptr) {}; and then give that lambda as destroy function to the shared pointer, but that feels a kind of stupid.
Well, alternative to no-op deleter might be using aliasing shared pointer
template <class U> shared_ptr (const shared_ptr<U>& x, element_type* p) noexcept;
It shares x, but after get() you'll get back p.
Discussion: What is shared_ptr's aliasing constructor for?
You probably just don't need a std::shared_ptr. And you probably don't even need a pointer.
As I read your question and comments, I don't see any point against
auto& my_input_stream = *( g_io_stream_get_input_stream(G_IO_STREAM(my_connection.get())) )
It is true that pointers allow optional data. However, it's also true that it's mostly used the wrong way. Having
void foo( type* ptr)
{
if (!ptr)
throw exception;
}
often doesn't make sense. If the function has to to work on concrete data, allowing a NULL parameter is only useful if you then worry about providing that data. Otherwise, just require a reference (possibly const) to the object.
Smart pointers are useful; but they're still pointers. Avoiding them altogether, if possible, is even better.
From the comments:
However, a reference must always be initialized
Absolutely. Since C++11 though we've got std::reference_wrapper which can also be reassinged and stored in containers.
You can use a deleter type that does nothing, but it will need to be passed as an argument to the shared_ptr's constructor
struct DoNothing {
template <typename T>
void operator()(T*) const noexcept { }
};
When creating a shared_ptr you will need to create one of these deleters and pass it in the constructor (as you're doing with the lambda). You can make this easier on yourself with an intermediate function
template <typename T>
std::shared_ptr<T> non_deleting_shared_ptr(T* ptr) {
return {ptr, DoNothing};
}
auto my_input_stream =
non_deleting_shared_ptr(
g_io_stream_get_input_stream(G_IO_STREAM(my_connection.get()));
However the bigger question is why you're using smart pointers when you don't want ownership to be a part of it. You'd almost certainly be better off with just a GAsyncQueue*, unless of course you're in a situation where you have a shared_ptr that needs to free sometimes. Like a data member maybe?
I work with a codebase that was partially implemented by someone who was in love with overly complex solutions to simple problems (e.g. template classes with two parameters that were only ever instantiated for one pair of types). One thing she did was to create objects in a smart pointer, and then have the object store a weak pointer to itself.
class MyClass {
//...
boost::weak_ptr<MyClass> m_self;
//...
};
boost::shared_ptr<MyClass>
Factory::Factory::Factory::CreateMyClass() {
boost::shared_ptr<MyClass> obj(new MyClass(...));
boost::weak_ptr<MyClass> p(obj);
obj->storeSelfPointer(p);
return obj;
}
The class then proceeds to use m_self by locking it and passing around the resulting shared pointer.
For the life of me, I cannot fathom what she was trying to accomplish. Is there some pattern or idea that would explain this implementation? It looks to me like this is completely pointless and I'd like to refactor it away.
EDIT: I should mention that none of the places that use the resulting smart pointer obtained from locking m_self actually retain the smart pointer.
A possible use of this "design" could be to use m_self.lock() to generate shared pointers from this.
If you remove this weak pointer member, the reference count hold by the generated shared pointer from this would be incorrect.
It achieves the same than std::enable_shared_from_this, interestingly enough, cppreference.com mentions this design :
A common implementation for enable_shared_from_this is to hold a weak
reference (such as std::weak_ptr) to this. The constructors of
std::shared_ptr detect the presence of an enable_shared_from_this base
and assign the newly created std::shared_ptr to the internally stored
weak reference
And the C++ standard, section § 20.8.2.4 10 , mention the same possible implementation :
The shared_ptr constructors that create unique pointers can detect the
presence of an enable_shared_- from_this base and assign the newly
created shared_ptr to its
__weak_this member
Possible Refactoring :
If you are using C++11, you can remove the std::weak_ptr member, and publicly inherits from std::enable_shared_from_this<T>. You should retrieve a shared pointer from this by calling shared_from_this().
If you are not using C++11 but can use boost, use boost::enable_shared_from_this, see the boost documentation. You should retrieve a shared pointer from this by calling shared_from_this().
If you are not using C++11, and can't use boost, you can bring the proposed implementation of the standard to your code base, it is short enough :
Code : (copied from § 20.8.2.4 - 11, remove leading underscores, and you probably want to rename it)
template<class T> class enable_shared_from_this {
private:
weak_ptr<T> __weak_this;
protected:
constexpr enable_shared_from_this() : __weak_this() { }
enable_shared_from_this(enable_shared_from_this const &) { }
enable_shared_from_this& operator=(enable_shared_from_this const &) { return *this; }
~enable_shared_from_this() { }
public:
shared_ptr<T> shared_from_this() { return shared_ptr<T>(__weak_this); }
shared_ptr<T const> shared_from_this() const { return shared_ptr<T const>(__weak_this); }
};
And use shared_from_this() to make a shared pointer. If you do copy this code, note that constructing shared pointers from this by other means would not work. The shared pointers constructors need to be modified (as explain by the standard quote above).
I have created a smart pointer class like:
template <class T>
class Owner
{
T* m_p;
public:
Owner(T *p=0) : m_p(p) {}
~Owner() { if (m_p) delete m_p; }
T* operator ->() { return m_p; }
T& operator *() { return *m_p; }
// other members.
};
It works well (resembles to the auto_ptr in boost library), but now I have the requirements that I want to store an dynamic array of smart pointers in an obj, and it must support:
1) insert new smart pointer into the smart pointers array to let the array resize and acquire the ownership of the new obj,
2) delete one smart pointer on the fly and the resource get freed,
3) when finalizing the array, all objects get deleted.
I was thinking using std::vector<Owner<T> >, but seems c++ best practice suggests not storing smart pointers in std containers, because copy/assignment behaviors, so what other things can I employ to implement this? something like the OwnerArr in the below example:
class Adapter;
class Computer
{
public:
Computer() {}
~Computer() { // adapters get freed automatically here. }
void insertAdapter(Adapter* pAdapter) { m_adapters->appendOne(pAdapter); }
OwnerArr<Adapter> m_adapters;
};
Thanks in advance!
You can't store your Owner, or std::auto_ptr (which you shouldn't use anyway, since it's deprecated), in a standard container because they are not really copyable.
In C++11, there's std::unique_ptr: a single-ownership smart pointer to replace auto_ptr, which is movable but not copyable. This can be moved or emplaced into any container, as long as you don't need to do anything that involves copying it. If you need multiple pointers to share ownership of the same object, then you can use std::shared_ptr instead.
If you're stuck with an older language version for some reason, then Boost can give you smart pointers, including a shared_ptr very similar to the standard one, or pointer containers similar to your OwnerArray.
If you do decide to roll your own resource management classes, always remember the Rule of Three. The classes you show have implicitly generated copy constructors and copy-assignment operators which can cause two pointers to own - and try to delete - the same object, which is very bad. You need to either prevent copying (by deleting these functions, or (pre-2011) declaring them private with no implementation), or implement some kind of safe copy semantics.
I have a set of shared pointers:
std::set<boost::shared_ptr<T>> set;
And a pointer:
T* p;
I would like to efficiently remove the element of set equal to p, but I can't do this with any of the members of set, or any of the standard algorithms, since T* is a completely different type to boost::shared_ptr<T>.
A few approaches I can think of are:
somehow constructing a new shared_ptr from the pointer that won't take ownership of the pointed to memory (ideal solution, but I can't see how to do this)
wrapping / re-implementing shared_ptr so that I can do the above
just doing my own binary search over the set
Construct a shared_ptr<T> from T with a null_deleter (see boost:::shared_ptr FAQ).
struct null_deleter {
void operator()(void const *) const { }
};
size_t remove_ptr_from_set(std::set<boost::shared_ptr<T>> &set, X* x)
{
shared_ptr<X> px(x, null_deleter());
return set.erase(px);
}
That way the types are compatible and you don't have to worry about your temporary shared_ptr deleting any object.
Or, as one of the comments say, if you can change T to inherit from enable_shared_from_this you could get a correct shared ptr from your object.
If the reason for using the set is that you need to efficiently find pointers of type T, then the obvious answer is not to make it a set of shared pointers! Instead, wrap the set in a class which manages the lifetimes of the pointers that the set contains.
You can use boost::ptr_set if you want the set to have ownership of the objects, or boost::reference_wrapper if you just want the set to store references to them. If you use shared_ptr in one place in your code, you will have to use it in all places, or risk terrible crashes (dangling pointers, already deleted objects etc.). The exception is weak_ptr, a pointer that points to an object held by a shared_ptr but does not share ownership.
For legacy reasons I need to use intrusive pointers, as I need the ability to convert raw pointers to smart pointers.
However I noticed there is no weak intrusive pointer for boost. I did find a talk about it on the boost thread list, however nothing concrete.
Does anyone know of a thread safe implementation of weak intrusive pointer?
Thanks
Rich
It does not make any sense.
To elaborate: weak_ptr points to the same instance of a counter object that shared_ptr do. When the shared_ptr goes out of scope, the instance of the counter stays (with a count effectively at 0), which allows the weak_ptr instances to check that they effectively point to a freed object.
With Intrusive Counting, the counter is integrated within the object. When the count reaches 0, the object is usually either recycled or deleted... but the point is the counter is no longer available. The rationale is that this allow for a more efficient storage (1 single chunk) and greater speed (cache locality).
If you need Weak Reference counting and do not care for the benefits of intrusive counting, you can use a combination of shared_ptr and weak_ptr.
The idea is to deassociate the counter from the objects.
class Counted
{
// bla
private:
boost::shared_ptr<int> mCounter;
};
Now you can return weak handles:
class WeakHandle
{
public:
explicit WeakHandle(Counted& c): mCounter(c.mCounter), mObject(&c) {}
bool expired() const { return mCounter.expired(); }
private:
boost::weak_ptr<int> mCounter;
Counted* mObject;
};
Here, we deassociate the lifetime of the counter from the lifetime of the object, so that it will survive the destruction of the object... partially. Thus making the weak_ptr effectively possible.
And of course, using shared_ptr and weak_ptr this is Thread Safe ;)
I didn't really like either of the previous answers so:
No, I don't know of an implementation, but I think it is possible. The standard implementation of the shared_ptr holds two reference counts, one for the "strong" and one for the "weak" references, and a pointer to the referent. In an intrusive_ptr implementation the strong count needs to be part of the object, but the weak can't be. So, it seems like you could create a "weakable" intrusive_ptr.
Define a weak pointer helper:
template<class X>
class intrusive_ptr_weak_helper {
long weak_ref_count;
X *target_instance;
};
Then record that into the object beside the reference count:
struct X {
...
intrusive_ptr_weak_helper *ref_weak_helper;
...
long ref_count;
...
};
When constructing X:
ref_count = 0;
ref_weak_helper = NULL;
The "strong" pointer, intrusive_strong_ptr, is identical to intrusive_ptr, until deletion occurs. When the strong ref count goes to zero (before deletion occurs):
if (ref_weak_helper != NULL) {
if (ref_weak_helper->weak_ref_count == 0)
delete ref_weak_helper;
else
ref_weak_helper->target_instance = NULL;
}
The "weak" version, intrusive_weak_ptr, records the pointer to the weak helper, manipulating that reference count, and accessing the target object via the target_instance pointer. When the weak_ref_count decrements to zero the status of target_instance determines whether the helper is deleted or not.
There are many details missing (concurrency concerns for instance) but this is a mixing of the shared_ptr and the intrusive_ptr. It maintains the basic benefits of the intrusive_ptr (cache optimization, reuse of 3rd party intrusive (strong) ref count, strong and weak pointer stand-ins are pointer sized) while adding extra work mainly in the weak reference path.
Current implementation of intrusive pointer is using reference counter. So deleting object delete also delete the counter, so weak_intrusive_pointer will never know that the object was deleted.
If you need to get weak_ptr from this, you probably search boost::enable_shared_from_this<T>.
OpenSceneGraph and its successor, VulkanSceneGraph, each have comprehensive implementations of intrusive strong pointers and associated weak pointers, named ref_ptr<> and observer_ptr<>, respectively.
I don't know every detail of these systems, but it seems they work using an additional object which is informed when the referent (a descendant of the class Referenced) is deleted. Weak pointers use this third object when an attempt is made to convert them to strong pointers.
VulkanSceneGraph is the next generation scene graph that is currently in development and intended to replace OpenSceneGraph, so I assume its intrusive pointer system is a more advanced implementation.
Worth checking out:
https://github.com/vsg-dev/VulkanSceneGraph/blob/master/include/vsg/core/observer_ptr.h