Document directory
- Class STD: tr1: shared_ptr
Class STD: tr1: shared_ptr
ASharted_ptrObject has the ownership of an object if:
- It was constructed with a pointer to that resource
- It was constructed fromShared_ptrObject that owns that resource
- It was constructed fromWeak_ptrObject that points to that resource
- Ownership of that resource was assigned to it, eitherShared_ptr: Operator =Or by calling the member functionShared_ptr: reset ().
All the shared pointer objects that share the ownership of the same resource also shared a control block, containing the number of shared_ptr objects that own the resource, the number of weak_ptr objects that point to the resource, and the deleter (a function used to release the resource), if it has one. an emptyShared_ptrObject does not own any resources and has no control block. On the other hand,Shared_ptrThat was initialized with a null pointer has a control block; this means it is not an empty shared pointer. when the reference counter to a resource becomes 0 (regardless the number of weak pointer still referring the object), the resource is released, either by deleting it or by passing its addresto sed the deleter.
Creating a shared_ptr
There are several constructors available forShared_ptr:
shared_ptr();template<class Other> explicit shared_ptr(Other*);template<class Other, class D> shared_ptr(Other*, D);shared_ptr(const shared_ptr&);template<class Other> shared_ptr(const shared_ptr<Other>&);template<class Other> shared_ptr(const weak_ptr<Other>&);template<class Other> shared_ptr(const std::auto_ptr<Other>&);
You basically can create a newShared_ptrFrom:
- A pointer to any type T (including const T), having the possibility of specifying a deleter for the pointed Resource
- AnotherShared_ptrObject
- AWeak_ptrObject
- AnAuto_ptrObject
The next sample showsShared_ptrCreated fromAuto_ptrObject. The auto pointer gives up the ownership of the resource, resetting its wrapped pointer to null.
int main(){ std::auto_ptr<foo> ap1(new foo); ap1->print(); std::cout << "ap1 pointer: " << ap1.get() << std::endl; std::tr1::shared_ptr<foo> sp1(ap1); sp1->print(); std::cout << "ap1 pointer: " << ap1.get() << std::endl; std::cout << "sp1 pointer: " << sp1.get() << std::endl; return 0;}
The output is:
foo::printap1 pointer: 0033A790foo::printap1 pointer: 00000000sp1 pointer: 0033A790
I was saying earlier that, whenShared_ptrObject is created, you can specify a special function called deleter, used to release the resource. If no such function is provided, the resource is simply deleted by calling operator Delete.
Consider, for instance, a case when the creation and deletion of a resource shocould be logged somewhere. for Class Foo defined at the beginning at the article I created a helper class, that creates and destroys instances, but also logs these events.
class foo_handler{public: static foo* alloc() { foo* f = new foo; ::OutputDebugString(_T("a new foo was created/n")); return f; } static void free(foo* f) { delete f; ::OutputDebugString(_T("foo destroyed/n")); }};
Each time a new object is created or destroyed, a message is printed in the output window (for simplicity, you will ignore the copy construction or assignment). FunctionFoo_handler: freeCan PE provided as a Delete toShared_ptrConstructor. As a result, when the resource is deleted a message is printed in the output window (You have to run in debugger to see it ).
int main(){ std::tr1::shared_ptr<foo> ptr( foo_handler::alloc(), &foo_handler::free); ptr->print(); return 0;}
Running in debugger and looking into the output window, you can see:
a new foo was createdfoo destroyed
FunctionGet_deleterFrom Header<Memory>Returns a pointer to the deleter ofShared_ptr, If one was provided, or 0 otherwise. the next sample shows how to get the deleter of the shared pointer created earlier.
typedef void (*deleter)(foo*);deleter* del = std::tr1::get_deleter<deleter>(ptr);std::cout << "get_deleter(ptr) != 0 == " << std::boolalpha << (del != 0) << std::endl;
The output is:
get_deleter(ptr) != 0 == true
Operators-> and * and function get
ClassShared_ptrOverloads operators-> and *, the first returning a pointer to the resource and the second a reference to the value of the resource, so that accessing the internal wrapped pointer is not necessary.
template<class Ty> class shared_ptr {public: Ty *get() const; Ty& operator*() const; Ty *operator->() const;};
FunctionGet ()Returns the wrapped pointer to the resource (basically identical to operator-> and available for compatibilityAuto_ptr).
std::tr1::shared_ptr<foo> sp(new foo); foo* f = sp.get(); if(f) f->print();
Conditional Operator
ClassShared_ptrDefines a bool operator that allows shared pointers to be used in Boolean expressions.Auto_ptr, That is not possible; you have to use function get () to access the internal pointer and check it against null.
void is_empty(std::tr1::shared_ptr<std::string> ptr){ if(ptr) { std::cout << "not empty" << std::endl; } else { std::cout << "is empty" << std::endl; }}int main(){ std::tr1::shared_ptr<std::string> sp1; std::tr1::shared_ptr<std::string> sp2(new std::string("demo")); is_empty(sp1); is_empty(sp2); return 0;}
The output is:
is emptynot empty
Swap and assignment
MethodSwap ()And the function with the same name From Header<Memory>Exchange the content of the shared pointers.
int main(){ std::tr1::shared_ptr<std::string> sp1; std::tr1::shared_ptr<std::string> sp2(new std::string("demo")); is_empty(sp1); is_empty(sp2); sp1.swap(sp2); is_empty(sp1); is_empty(sp2); return 0;}
The output is:
is emptynot emptynot emptyis empty
On the other hand, operator = is overloaded so that a shared pointer can be assigned from anotherShared_ptrOrAuto_ptr.
template<class Ty> class shared_ptr{public: shared_ptr& operator=(const shared_ptr&); template<class Other> shared_ptr& operator=(const shared_ptr<Other>&); template<class Other> shared_ptr& operator=(auto_ptr<Other>&);}
The next sample shows an example of using operator =.
int main(){ std::tr1::shared_ptr<int> sp1(new int(1)); std::cout << "sp1 = " << *sp1 << std::endl; std::tr1::shared_ptr<int> sp2(new int(2)); std::cout << "sp2 = " << *sp2 << std::endl; sp1 = sp2; std::cout << "sp1 = " << *sp1 << std::endl; return 0;}
Methods unique and use_count
MethodUse_count ()Returns the number of references to the shared resource (pointed by the current shared pointer object). MethodUnique ()Indicates whether another shared pointed shares the ownership of the same resource or not (basically, it's identical to 1 = use_count ()).
int main(){ std::tr1::shared_ptr<std::string> sp1(new std::string("marius bancila")); std::cout << "unique : " << std::boolalpha << sp1.unique() << std::endl; std::cout << "counter : " << sp1.use_count() << std::endl; std::tr1::shared_ptr<std::string> sp2(sp1); std::cout << "unique : " << std::boolalpha << sp1.unique() << std::endl; std::cout << "counter : " << sp1.use_count() << std::endl; return 0;}
The output is:
unique : truecounter : 1unique : falsecounter : 2
Resetting
FunctionReset ()Decrements the shared reference counter. It then transforms the shared pointer to an emptyShared_ptr.
int main(){ // a shared_ptr owns the resouce, counter is 1 std::tr1::shared_ptr<foo> sp1(new foo); std::cout << "counter sp1: " << sp1.use_count() << std::endl; // a second shared_ptr owns the resourse, shared counter is 2 std::tr1::shared_ptr<foo> sp2(sp1); std::cout << "counter sp1: " << sp1.use_count() << std::endl; std::cout << "counter sp2: " << sp2.use_count() << std::endl; // first shared_ptr is reset, the counter decremented // and the object becomes empty (no control block anymore) sp1.reset(); std::cout << "counter sp1: " << sp1.use_count() << std::endl; std::cout << "counter sp2: " << sp2.use_count() << std::endl; return 0;}
The output is:
counter sp1: 1counter sp1: 2counter sp2: 2counter sp1: 0counter sp2: 1