Overview
shared_ptr are useful when a resource such as a piece of memory or a file handle can be collectively shared by multiple owners.
Details
Sometimes a resource needs to be shared across without duplication. An unique_ptr discussed above cannot be used in such cases.
For example, a chat server needs to share a message its clients without duplication.
shared_ptr addresses this issue. Unlike a unique_ptr, the underlying resource is collectively owned by a set of shared_ptrs. The underlying resource is released when the last instance of shared_ptr goes out of scope.
For example, a chat server needs to share a message its clients without duplication.
shared_ptr addresses this issue. Unlike a unique_ptr, the underlying resource is collectively owned by a set of shared_ptrs. The underlying resource is released when the last instance of shared_ptr goes out of scope.
shared_ptr
Syntax
template <class T> class shared_ptr
member types
Name | Description |
---|---|
element_type | first template parameter (T). The type of the managed object |
Constructors
Commonly used constructors. Some support custom allocators.
Name | Description |
---|---|
shared_ptr() | default constructor. use_count() is 0. Example: shared_ptr<int>() |
shared_ptr (nullptr_t) | same as default constructor. Example: shared_ptr<int>(nullptr) |
template <class U> shared_ptr (U* p) | takes ownership of p and use default deleter. use_count() is 1. Example: shared_ptr<int>(new int) |
template <class U, class D> shared_ptr (U* p, D del) | takes ownership of p and use deleter del. use_count() is 1. Example: auto d = default_delete<int>(); shared_ptr<int> (new int, d); |
template <class D> shared_ptr (nullptr_t, D del) | same as default but uses deleter del. use_count() is 0. Example: auto d = default_delete<int>(); shared_ptr<int> (nullptr, d); |
shared_ptr (const shared_ptr& x) | copy constructor. shares pointer and deleter from x. increments use_count(). Example: auto d = default_delete<int>(); shared_ptr<int> x(new int, d); shared_ptr<int> (x); |
template <class U> shared_ptr (const shared_ptr<U>& x) | copy constructor. shares pointer and deleter from x. Example: auto d = default_delete<int>(); shared_ptr<int> (shared_ptr<int> (new int, d)); |
shared_ptr (shared_ptr&& x) | move constructor. move pointer and deleter from x. x becomes empty. Example: shared_ptr<int> x(new int, default_delete<int>()); shared_ptr<int> (move(x)) |
shared_ptr (const shared_ptr<U>&& x) | move constructor. move pointer and deleter from x. x becomes empty. Example: auto d = default_delete<int>(); shared_ptr<int>(shared_ptr<int> (new int, d)); |
template <class U> shared_ptr(const weak_ptr<U>& x) | same as copy constructor. exception on thrown if x has expired. Example: shared_ptr<int> x (new int); weak_ptr<int> w(x); shared_ptr<int> y (w); |
template <class U> shared_ptr(auto_ptr<U>&& x) | takes ownership from x. uses default deleter and use_count() is 1. Example: shared_ptr<int> (auto_ptr<int> (new int)); |
template <class U, class D> shared_ptr(unique_ptr<T,D>&& x) | takes ownership from x and use_count() is 1. Example: shared_ptr<int> (unique_ptr<int> (new int, default_delete<int>())); |
template <class U> shared_ptr (const shared_ptr<U>& x, element_type *p) | Unlike shared_ptr constructors discussed above, an aliasing constructor co owns internal member object of shared_ptr x. It also increments its use_count(). In the example below, the owned object will be share_ptr x and the stored object will be x->data. In this case the get() will return stored object. Example: struct S {int data;}; shared_ptr<S> x(new S); shared_ptr<int> (x, x->data); |
Methods
The following describes functionality in detail.
Name | Description |
---|---|
element_type* get() | Returns the pointer of the resource it's holding without relinquishing the ownership. Example auto sp{shared_ptr<int>(new int(10))}; //prints 10 cout << *sp.get() << endl; |
bool unique() | Checks if use_count() is 1. Example cout << boolalpha; auto sp{shared_ptr<int>(new int(10))}; //prints true cout << sp.unique() << endl; //prints false cout << shared_ptr<int>(sp).unique() << endl; |
long int use_count() | Returns number of instances of shared_ptr sharing the resource. Example auto sp{shared_ptr<int>(new int(10))}; //prints 1 cout << sp.use_count() << endl; //prints 2 cout << shared_ptr<int>(sp).use_count() << endl; |
| Applies to alias based constructs. When two shared_ptrs or weak_ptrs are compared using operator <, value based comparison is applied which compares the stored objects. Whereas owner_before() uses owner_based comparison that compares the owner share_ptr objects instead. Two of these aliased shared_ptr or weak_ptr are considered equivalent (i.e., this function returns false no matter the order of the operands) if they both share ownership, or they are both empty. Example cout << boolalpha;//1 auto sp{shared_ptr<int>{new int{10}}}; auto sp2{shared_ptr<int>{sp,new int {20}}}; auto sp3{shared_ptr<int>{sp,new int {30}}}; //prints *sp2 = 20 *sp3 = 30 cout << "*sp2 = " << *sp2 << " *sp3 = " << *sp3 << endl; //prints true cout << (sp2 < sp3) << endl; //prints false cout << sp2.owner_before(sp3) << endl; cout << sp3.owner_before(sp2) << endl; cout << endl; //2 auto wp2{weak_ptr<int>{sp2}}; auto wp3{weak_ptr<int>{sp3}}; //prints false cout << wp2.owner_before(wp3) << endl; //prints false cout << wp3.owner_before(wp2) << endl; |
| Destroys the resource it's currently holding by calling deleter and releases the resource. Optionally new resource can be set to it.
struct product{int id;}; template<> struct std::default_delete<product> { void operator()(product *p) { cout << "deleting product id: " << p->id << endl; delete p; } }; shared_ptr<product> sp; //1 sp.reset(new product(20)); //2 sp.reset(new product(30),default_delete<product>()); //prints:deleting product id: 30 //3 sp.reset(); |
operator bool() | Can be used to check if the use_count() is 1 or more. Example shared_ptr<int> sp; cout << boolalpha; //prints false cout << (bool)sp << endl; sp.reset(new int); //prints true cout << (bool)sp << endl; |
element_type& operator *() | Object dereferencing. Example shared_ptr<int> sp(new int(20)); //prints 20 cout << *sp; |
element_type* operator ->() | Member dereferencing. Example shared_ptr<pair<int,int>> sp(new pair<int,int> {10,20}); //prints 20 cout << sp->second; |
element_type& operator [] (size_t index) | Array accessing index operator. Available only in specialized constructs. Example shared_ptr<int[]> sp(new int[10]); sp[5]=20; //prints 20 cout << sp[5]; |
| Assignment Operator. Example shared_ptr<int> sp (new int(10)); shared_ptr<int> sp2; //1 sp2=sp; //prints sp = 10 sp2= 10 cout << "sp = " << *sp << " sp2= " << *sp2 << endl; //2 sp2 = shared_ptr<int>(new int(20)); //prints sp2= 20 cout << "sp2= " << *sp2 << endl; //3 sp2 = move(sp); //prints sp2= 10 cout << "sp2= " << *sp2 << endl; //4 sp2 = move(shared_ptr<int>(new int(30))); //prints sp2= 30 cout << "sp2= " << *sp2 << endl; //6 sp2 = move(unique_ptr<int>(new int(40), default_delete<int>())); //prints sp2= 40 cout << "sp2= " << *sp2 << endl; |
External Methods
The following describes relational operators.
Name | Description |
---|---|
| Equality operator. |
| Inequality operator. |
| Greater than operator. |
| Greater than or equal to operator. |
| Less than operator. |
| Less than or equal to operator. |
make_shared() template function enables creation of shared_ptr and initializing it by passing by passing argument list.
Syntax
template< class T, class... Args > shared_ptr<T> make_shared( Args&&... args );
Example
auto sp = make_shared<pair<int,int>>(10,20); //prints 10 20 cout << sp->first << " " << sp->second << endl;
Similar to make_shared(), allocate_shared() template function enables creation of shared_ptr and initializing it by passing by passing argument list. However it uses a custom allocator.
Syntax
template <class T, class Alloc, class... Args> shared_ptr<T> allocate_shared (const Alloc& alloc, Args&&... args);
Example
allocator<int> alloc; auto sp = allocate_shared<int> (alloc,10);
These are similar to cast functions such as static, dynamic and const except applies to resource owned by a shared_ptr.
Syntax
template <class T, class U> shared_ptr<T> static_pointer_cast (const shared_ptr<U>& sp) template <class T, class U> shared_ptr<T> dynamic_pointer_cast (const shared_ptr<U>& sp) template <class T, class U> shared_ptr<T> const_pointer_cast (const shared_ptr<U>& sp)
When applied it creates new shared_ptr<T> object after applying cast on shared_ptr<U> . The use_count() is incremented.
Example
struct base { void print() {cout << "base" << endl;} //needed for dynamic_cast virtual ~base(){} }; struct derived:public base {//const needed for const cast
void print() const {cout << "derived" << endl;} //needed for dynamic cast virtual ~derived(){} } d; auto spd = make_shared<derived>(d); auto spb = static_pointer_cast<base>(spd); //prints 2 cout << spb.use_count() << endl; //prints base spb->print(); auto spd2 = dynamic_pointer_cast<derived>(spb); //prints 3 cout << spd2.use_count() << endl; //prints derived spd2->print(); auto spd3 = const_pointer_cast<const derived>(spd2); //prints 4 cout << spd3.use_count() << endl; //prints derived spd3->print();
owner_less
As discussed earlier, aliasing constructs and owner_before() of use owner based comparison. owner_less define functor objects that use owner based comparison while comparing shared_ptr or weak_ptr.
This is a replacement for less (or operator<) to be used for these types when sorting needs to be based on their owned pointer instead of their stored pointer (which is what is compared by operator<).
Syntax
//Ptr The type of the managed pointers to be ordered according to owned resource, aliased as member types first_argument_type and second_argument_type. template <class Ptr> struct owner_less//T The type of object pointed by the managed pointer type.
//specialization of shared_ptr
template <class T>struct owner_less<shared_ptr<T>>//specialization of weak_ptr
template <class T> struct owner_less<weak_ptr<T>>
member types
Name | Description |
---|---|
result_type | bool indicating result of the operation. |
first_argument_type | first template parameter (Ptr). This can be either shared_ptr<T> or weak_ptr<T>. |
second_argument_type | second template parameter (Ptr). This can be either shared_ptr<T> or weak_ptr<T>. |
methods
The comparison is provided by overloaded operator () function. Returns true if the first argument is considered to go before the second argument in a strict weak ordering based on their owned pointers.
The function uses shared_ptr::owner_before and/or weak_ptr::owner_before to determine this order.
Name | Description |
---|---|
bool operator() (const shared_ptr<T>& lhs, const shared_ptr<T>& rhs ) | specialization of shared_ptr |
bool operator() (const weak_ptr<T>& lhs, const weak_ptr<T>& rhs ) | specialization of weak_ptr |
| specialization of shared_ptr and weak_ptr. |
Consider the following scenario.
- An instance of shared_ptr x is created from class C.
- class C defines a method getptr() that returns shared_ptr from self.
- Another instance of shared_ptr y is created from x.
struct C { shared_ptr<C> getptr() { return shared_ptr<C>(this); } }; auto x = make_shared<C>(); //prints 1 cout << x.use_count(); auto y = x->getptr(); //prints 1 cout << y.use_count();
This is depicted in example 11.
To get around this issue, enable_shared_from_this class is introduced. All the classes that intend to create a shared_ptr from self should derive from this class.
syntax
template< class T > class enable_shared_from_this
Constructors
Commonly used constructors. Some support custom allocators.
Name | Description |
---|---|
enable_shared_from_this() | default constructor. Example struct C:public enable_shared_from_this<C> { shared_ptr<C> getptr() { return shared_from_this(); } }; |
enable_shared_from_this (const enable_shared_from_this&) | copy constructor. |
Methods
It provides a single method, shared_from_this() to return a shared_ptr with use_count() increment.
Name | Description |
---|---|
shared_ptr <T> shared_from_this() | Constructs and returns a shared_ptr object pointing to *this and sharing ownership with existing shared_ptr objects. Example struct C:public enable_shared_from_this<C> { shared_ptr<C> getptr() { return shared_from_this(); } }; auto x = make_shared<C>(); //prints 1 cout << x.use_count(); auto y = x->getptr(); //prints 2 cout << y.use_count(); |
Usage Example
linked list
As implemented using unique_ptr, a double linked list can also be implemented using shared_ptr .
The same strategy also implies here to avoid double referencing as shown below.
struct doublelist { struct node; using LLNODE = shared_ptr<node>; using LLNODEptr = shared_ptr<node>*;
struct node { T data; LLNODEptr prev; LLNODE next; }; LLNODE head; LLNODEptr tail; }
The example 13 depicts a solution.
A chat server needs to share a message with its clients without duplication.
The solution is to use shared_ptr for sharing the message across the clients.
As seen in its console output, a chaat server publishes a message with its 3 clients. Instead of duplicating the message, it's forwarded as shared_ptr to the clients. After all the instances of shared pointer are destroyed, deleter is called.
No comments:
Post a Comment