Class std::tr1::shared_ptr
A sharted_ptr object has the ownership of an object if:
- It was constructed with a pointer to that resource
- It was constructed from a shared_ptr object that owns that resource
- It was constructed from a weak_ptr object that points to that resource
- Ownership of that resource was assigned to it, either with shared_ptr::operator= or by calling the member function shared_ptr::reset().
Creating a shared_ptr
There are several constructors available for a shared_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 new shared_ptr from:
- A pointer to any type T (including const T), having the possibility of specifying a deleter for the pointed resource
- Another shared_ptr object
- A weak_ptr object
- An auto_ptr object
The next sample shows a shared_ptr created from an auto_ptr object. 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::print ap1 pointer: 0033A790 foo::print ap1 pointer: 00000000 sp1 pointer: 0033A790
I was saying earlier that, when a shared_ptr object 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 should 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). Function foo_handler::free can pe provided as a delete to the shared_ptr constructor. 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 created
foo destroyed
Function get_deleter from header <memory> returns a pointer to the deleter of a shared_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
Class shared_ptr overloads 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; };
Function get() returns the wrapped pointer to the resource (basically identical to operator-> and available for compatibility with auto_ptr).
std::tr1::shared_ptr<foo> sp(new foo); foo* f = sp.get(); if(f) f->print();
Conditional operator
Class shared_ptr defines a bool operator that allows shared pointers to be used in boolean expressions. With 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 empty
not empty
Swap and assignment
Method swap() 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 empty not empty not empty is empty
On the other hand, operator= is overloaded so that a shared pointer can be assigned from another shared_ptr or auto_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
Method use_count() returns the number of references to the shared resource (pointed by the current shared pointer object). Method unique() 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 : true counter : 1 unique : false counter : 2
Resetting
Function reset() decrements the shared reference counter. It then transforms the shared pointer to an empty shared_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: 1 counter sp1: 2 counter sp2: 2 counter sp1: 0 counter sp2: 1

本文详细介绍了C++中智能指针shared_ptr的工作原理及使用方法。包括如何创建shared_ptr,其构造函数的不同形式,以及如何使用其提供的成员函数如use_count、unique等来检查资源引用计数和唯一性。此外还探讨了shared_ptr的运算符重载、资源释放机制以及reset方法的作用。
6万+

被折叠的 条评论
为什么被折叠?



