shared_ptr: Based on a reference counter model, with the counter incremented each time a new shared pointer object points to the resource, and decremented when the object's destructor executes; when the counter gets to 0, the resource is released. This pointer is copy constructable and assignable; this makes it usable in STL containers. Moreover, the shared pointer works with polymorphic types and incomplete types. Its major drawback is the impossibility to detect cyclic dependencies, in which case the resources never get released (for example, a tree with nodes having (shared) pointers to children but also to the parent, in which case the parent and the children are referencing each other, in a cycle). To fix this issue, a second smart pointer was created:
weak_ptr: Points to a resource referred by a shared pointer, but does not participate in reference counting. When the counters gets to 0, the resource is released, regardless the number of weak pointers referring it; all these pointers are marked as invalid.
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().
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;
1.get() 返回对象指针;use_count() 返回对象的引用计数
1. #include <iostream>
2. #include <tr1/memory>
3.
4. class Foo
5. {
6. public:
7. void print()
8. {
9. std::cout << " foo::print" << std::endl;
10. }
11. };
12.
13. /* When sp2 is created, sp1 increments the reference counter.
14. * When the two shared pointer objects get out of scope, the last
15. * one that is destroyed will release the resource.
16. *
17. * output:
18. * foo::print
19. * sp1 pointer: 0x90a7008
20. * foo::print
21. * sp1 pointer: 0x90a7008
22. * sp2 pointer: 0x90a7008
23. * counter sp1: 2
24. * counter sp2: 2
25. */
26. int main()
27. {
28. std::tr1::shared_ptr<Foo> sp1(new Foo);
29. sp1->print();
30. std::cout << "sp1 pointer: " << sp1.get() << std::endl;
31.
32. std::tr1::shared_ptr<Foo> sp2(sp1);
33. sp2->print();
34. std::cout << "sp1 pointer: " << sp1.get() << std::endl;
35. std::cout << "sp2 pointer: " << sp2.get() << std::endl;
36.
37. std::cout << "counter sp1: " << sp1.use_count() << std::endl;
38. std::cout << "counter sp2: " << sp2.use_count() << std::endl;
39.
40. return 0;
41. }
2.相比较shared_ptr,auto_ptr在赋值与别人后,是放弃对象引用的。
1. #include <iostream>
2. #include <tr1/memory>
3.
4. class Foo
5. {
6. public:
7. void print()
8. {
9. std::cout << " foo::print" << std::endl;
10. }
11. };
12.
13. /* The next sample shows a shared_ptr created from an auto_ptr object. The auto pointer gives up the ownership of the resource,
14. * resetting its wrapped pointer to NULL.
15. *
16. * output:
17. * foo::print
18. * ap1 pointer: 0x99b8008
19. * foo::print
20. * ap1 pointer: 0
21. * sp1 pointer: 0x99b8008
22. */
23. int main()
24. {
25. std::auto_ptr<Foo> ap1(new Foo);
26. ap1->print();
27. std::cout << "ap1 pointer: " << ap1.get() << std::endl;
28.
29. std::tr1::shared_ptr<Foo> sp1(ap1);
30. sp1->print();
31. std::cout << "ap1 pointer: " << ap1.get() << std::endl;
32. std::cout << "sp1 pointer: " << sp1.get() << std::endl;
33.
34. return 0;
35. }
3.在shared_ptr构造函数中,行参指定构造对象和析构对象的函数
1. #include <iostream>
2. #include <tr1/memory>
3.
4. class Foo
5. {
6. public:
7. void print()
8. {
9. std::cout << " foo::print" << std::endl;
10. }
11. };
12.
13. class FooHandler
14. {
15. public:
16. static Foo* alloc()
17. {
18. Foo* f = new Foo;
19. std::cout << " a new foo was created" << std::endl;
20. return f;
21. }
22.
23. static void free(Foo* f)
24. {
25. delete f;
26. std::cout << " foo destroyed" << std::endl;
27. }
28. };
29.
30. /*
31. * Each time a new object is created or destroyed, a message is printed in the output window (for simplicity, you will ignore the copy
32. * construction or assignment). Function FooHandler::free can be provided as a delete to the shared_ptr constructor. As a result,
33. * when the resource is deleted a message is printed in the output window (you have to run in debugger to see it).
34. *
35. * output:
36. * a new foo was created
37. * foo::print
38. * foo destroyed
39. */
40. int main()
41. {
42. std::tr1::shared_ptr<Foo> ptr(FooHandler::alloc(), &FooHandler::free);
43. ptr->print();
44.
45. return 0;
46. }
4.get() 返回对象指针,使用->调用成员函数
1. #include <iostream>
2. #include <tr1/memory>
3.
4. class Foo
5. {
6. public:
7. void print()
8. {
9. std::cout << " foo::print" << std::endl;
10. }
11. };
12.
13. /*
14. * Function get() returns the wrapped pointer to the resource (basically identical to operator-> and available for compatibility
15. * with auto_ptr).
16. *
17. * output:
18. * foo::print
19. */
20. int main()
21. {
22. std::tr1::shared_ptr<Foo> sp(new Foo);
23. Foo* f = sp.get();
24. if (f)
25. f->print();
26.
27. return 0;
28. }
5.get() 返回对象指针,if判断是否为null
1. #include <iostream>
2. #include <tr1/memory>
3.
4. /* Class shared_ptr defines a bool operator that allows shared pointers to be used in boolean expressions.
5. * With auto_ptr, that is not possible; you have to use function get() to access the internal pointer and check it against NULL.
6. */
7. class PtrUtil
8. {
9. public:
10. static void is_empty(std::tr1::shared_ptr<std::string> ptr)
11. {
12. if (ptr)
13. std::cout << "not empty" << std::endl;
14. else
15. std::cout << "is empty" << std::endl;
16. }
17. };
18.
19. /*
20. * output:
21. * is empty
22. * not empty
23. */
24. int main()
25. {
26. std::tr1::shared_ptr<std::string> sp1;
27. std::tr1::shared_ptr<std::string> sp2(new std::string("demo"));
28.
29. PtrUtil::is_empty(sp1);
30. PtrUtil::is_empty(sp2);
31.
32. return 0;
33. }
6.swap() 交换两个shared_ptr所指向的对象
1. #include <iostream>
2. #include <tr1/memory>
3.
4. class PtrUtil
5. {
6. public:
7. static void is_empty(std::tr1::shared_ptr<std::string> ptr)
8. {
9. if (ptr)
10. std::cout << "not empty" << std::endl;
11. else
12. std::cout << "is empty" << std::endl;
13. }
14. };
15.
16. /* Method swap() : exchange the content of the shared pointers.
17. *
18. * output:
19. * is empty
20. * not empty
21. * not empty
22. * is empty
23. */
24. int main()
25. {
26. std::tr1::shared_ptr<std::string> sp1;
27. std::tr1::shared_ptr<std::string> sp2(new std::string("demo"));
28.
29. PtrUtil::is_empty(sp1);
30. PtrUtil::is_empty(sp2);
31.
32. sp1.swap(sp2);
33.
34. PtrUtil::is_empty(sp1);
35. PtrUtil::is_empty(sp2);
36.
37. return 0;
38. }
7.使用等号赋值
1. #include <iostream>
2. #include <tr1/memory>
3.
4. /* operator= is overloaded so that a shared pointer can be assigned from another shared_ptr or auto_ptr.
5. *
6. * output:
7. * sp1 = 1
8. * sp2 = 2
9. * sp1 = 2
10. */
11. int main()
12. {
13. std::tr1::shared_ptr<int> sp1(new int(1));
14. std::cout << "sp1 = " << *sp1 << std::endl;
15.
16. std::tr1::shared_ptr<int> sp2(new int(2));
17. std::cout << "sp2 = " << *sp2 << std::endl;
18.
19. sp1 = sp2;
20. std::cout << "sp1 = " << *sp1 << std::endl;
21.
22. return 0;
23. }
8.unique() 判断当前对象的引用计数==1?
1. #include <iostream>
2. #include <tr1/memory>
3.
4. /* Method use_count() returns the number of references to the shared resource (pointed by the current shared pointer object).
5. * Method unique() indicates whether another shared pointed shares the ownership of the same resource or not
6. * (basically, it's identical to 1 == use_count()).
7. *
8. * output:
9. * unique : true
10. * counter : 1
11. * unique : false
12. * counter : 2
13. */
14. int main()
15. {
16. std::tr1::shared_ptr<std::string> sp1(new std::string("marius bancila"));
17. std::cout << "unique : " << std::boolalpha << sp1.unique() << std::endl;
18. std::cout << "counter : " << sp1.use_count() << std::endl;
19. std::tr1::shared_ptr<std::string> sp2(sp1);
20. std::cout << "unique : " << std::boolalpha << sp1.unique() << std::endl;
21. std::cout << "counter : " << sp1.use_count() << std::endl;
22.
23. return 0;
24. }
9.reset() 清空当前shared指针,并将所有基于该指针创建的shared指针的引用计数减1
1. #include <iostream>
2. #include <tr1/memory>
3.
4. class Foo
5. {
6. public:
7. void print()
8. {
9. std::cout << " foo::print" << std::endl;
10. }
11. };
12.
13. /*Function reset() decrements the shared reference counter. It then transforms the shared pointer to an empty shared_ptr.
14. *
15. * output:
16. * counter sp1: 1
17. * counter sp1: 3
18. * counter sp2: 3
19. * counter sp3: 3
20. * counter sp1: 0
21. * counter sp2: 2
22. * counter sp3: 2
23. * counter sp1: 0
24. * counter sp2: 0
25. * counter sp3: 1
26. */
27. int main()
28. {
29. // a shared_ptr owns the resouce, counter is 1
30. std::tr1::shared_ptr<Foo> sp1(new Foo);
31. std::cout << "counter sp1: " << sp1.use_count() << std::endl;
32.
33. std::tr1::shared_ptr<Foo> sp2(sp1);
34. std::tr1::shared_ptr<Foo> sp3(sp2);
35. std::cout << "counter sp1: " << sp1.use_count() << std::endl;
36. std::cout << "counter sp2: " << sp2.use_count() << std::endl;
37. std::cout << "counter sp3: " << sp3.use_count() << std::endl;
38.
39. // first shared_ptr is reset, the counter decremented and the object becomes empty
40. sp1.reset();
41. std::cout << "counter sp1: " << sp1.use_count() << std::endl;
42. std::cout << "counter sp2: " << sp2.use_count() << std::endl;
43. std::cout << "counter sp3: " << sp3.use_count() << std::endl;
44.
45. sp2.reset();
46. std::cout << "counter sp1: " << sp1.use_count() << std::endl;
47. std::cout << "counter sp2: " << sp2.use_count() << std::endl;
48. std::cout << "counter sp3: " << sp3.use_count() << std::endl;
49.
50. return 0;
51. }
10.对引用计数的理解,在容器中使用shared_ptr
1. #include <iostream>
2. #include <tr1/memory>
3. #include <vector>
4. #include <algorithm>
5.
6. /* The following sample shows a vector of shared_ptr to int; a transformation is applied on the elements of the vector,
7. * doubling the value of the pointed objects.
8. *
9. * The program shows the reference counter to show that calling function double_it() does not affect it, even though this function
10. * returns a shared_ptr by value.
11. */
12. std::tr1::shared_ptr<int> double_it(const std::tr1::shared_ptr<int>& sp)
13. {
14. *sp *= 2;
15. return sp;
16. }
17.
18. /*
19. * output:
20. * initially
21. * 1 (counter = 1)
22. * 2 (counter = 1)
23. * 3 (counter = 1)
24. * after transformation
25. * 2 (counter = 1)
26. * 4 (counter = 1)
27. * 6 (counter = 1)
28. */
29. int main()
30. {
31. std::vector<std::tr1::shared_ptr<int> > numbers;
32.
33. numbers.push_back(std::tr1::shared_ptr<int>(new int(1)));
34. numbers.push_back(std::tr1::shared_ptr<int>(new int(2)));
35. numbers.push_back(std::tr1::shared_ptr<int>(new int(3)));
36.
37. std::cout << "initially" << std::endl;
38. for (std::vector<std::tr1::shared_ptr<int> >::const_iterator it =
39. numbers.begin(); it != numbers.end(); ++it)
40. std::cout << **it << " (counter = " << (*it).use_count() << ")"
41. << std::endl;
42. std::transform(numbers.begin(), numbers.end(), numbers.begin(), double_it);
43. std::cout << "after transformation" << std::endl;
44. for (std::vector<std::tr1::shared_ptr<int> >::const_iterator it =
45. numbers.begin(); it != numbers.end(); ++it)
46. std::cout << **it << " (counter = " << (*it).use_count() << ")"
47. << std::endl;
48.
49. return 0;
50. }
11.多态情况下的shared指针使用(声明基类句柄,创建子类对象)
1. #include <iostream>
2. #include <tr1/memory>
3. #include <vector>
4.
5. /*shared_ptr can work with class hierarchies, so that shared<D> is convertible to shared<B>, where D is a class (or struct) derived
6. * from B. The following class hierarchy is used to demonstrate the concept.
7. */
8. class Item
9. {
10. std::string title_;
11. public:
12. Item(const std::string& title) :
13. title_(title)
14. {
15. }
16. virtual ~Item()
17. {
18. }
19.
20. virtual std::string Description() const = 0;
21. std::string Title() const
22. {
23. return title_;
24. }
25. };
26.
27. class Book: public Item
28. {
29. int pages_;
30. public:
31. Book(const std::string& title, int pages) :
32. Item(title), pages_(pages)
33. {
34. }
35.
36. virtual std::string Description() const
37. {
38. return "Book: " + Title();
39. }
40. int Pages() const
41. {
42. return pages_;
43. }
44. };
45.
46. class DVD: public Item
47. {
48. int tracks_;
49. public:
50. DVD(const std::string& title, int tracks) :
51. Item(title), tracks_(tracks)
52. {
53. }
54.
55. virtual std::string Description() const
56. {
57. return "DVD: " + Title();
58. }
59. int Tracks() const
60. {
61. return tracks_;
62. }
63. };
64.
65. /*
66. * output:
67. * Book: Effective STL
68. * DVD: Left of the Middle
69. */
70. int main()
71. {
72. std::vector<std::tr1::shared_ptr<Item> > items;
73. items.push_back(std::tr1::shared_ptr<Book>(new Book("Effective STL", 400)));
74. items.push_back(std::tr1::shared_ptr<DVD>(new DVD("Left of the Middle", 14)));
75.
76. for (std::vector<std::tr1::shared_ptr<Item> >::const_iterator it =
77. items.begin(); it != items.end(); ++it)
78. std::cout << (*it)->Description() << std::endl;
79.
80. return 0;
81. }
12.dynamic_cast,使用dynamic_pointer_cast将基类向下转型为子类
1. #include <iostream>
2. #include <tr1/memory>
3. #include <vector>
4.
5. /*shared_ptr can work with class hierarchies, so that shared<D> is convertible to shared<B>, where D is a class (or struct) derived
6. * from B. The following class hierarchy is used to demonstrate the concept.
7. */
8. class Item
9. {
10. std::string title_;
11. public:
12. Item(const std::string& title) :
13. title_(title)
14. {
15. }
16. virtual ~Item()
17. {
18. }
19.
20. virtual std::string Description() const = 0;
21. std::string Title() const
22. {
23. return title_;
24. }
25. };
26.
27. class Book: public Item
28. {
29. int pages_;
30. public:
31. Book(const std::string& title, int pages) :
32. Item(title), pages_(pages)
33. {
34. }
35.
36. virtual std::string Description() const
37. {
38. return "Book: " + Title();
39. }
40. int Pages() const
41. {
42. return pages_;
43. }
44. };
45.
46. class DVD: public Item
47. {
48. int tracks_;
49. public:
50. DVD(const std::string& title, int tracks) :
51. Item(title), tracks_(tracks)
52. {
53. }
54.
55. virtual std::string Description() const
56. {
57. return "DVD: " + Title();
58. }
59. int Tracks() const
60. {
61. return tracks_;
62. }
63. };
64.
65. /* To convert back, from shared_ptr<B> to shared_ptr<D>, where D is a class (or structure) derived from B,
66. * you can use the cast function std::tr1::dynamic_pointer_cast.
67. *
68. * output:
69. * spi counter: 1
70. * Left of the Middle, 14 tracks
71. * spi counter: 2
72. * spb counter: 0
73. * spd counter: 2
74. */
75. int main()
76. {
77. std::tr1::shared_ptr<Item> spi(new DVD("Left of the Middle", 14));
78. std::cout << "spi counter: " << spi.use_count() << std::endl;
79. std::tr1::shared_ptr<Book> spb = std::tr1::dynamic_pointer_cast<Book>(spi);
80. if (spb)
81. std::cout << spb->Title() << ", " << spb->Pages() << " pages" << std::endl;
82.
83. std::tr1::shared_ptr<DVD> spd = std::tr1::dynamic_pointer_cast<DVD>(spi);
84. if (spd)
85. std::cout << spd->Title() << ", " << spd->Tracks() << " tracks" << std::endl;
86.
87. std::cout << "spi counter: " << spi.use_count() << std::endl;
88. std::cout << "spb counter: " << spb.use_count() << std::endl;
89. std::cout << "spd counter: " << spd.use_count() << std::endl;
90.
91. return 0;
92. }
13.static cast,使用static_pointer_cast将void转型为char,观察引用计数的变化
1. #include <iostream>
2. #include <tr1/memory>
3. #include <vector>
4.
5. /* A second cast function is std::tr1::static_pointer_cast. It returns an empty shared_ptr if the original object is empty,
6. * or a shared_ptr<T> object that owns the resource that is owned by the original object. The expression static_cast<T*>(r.get())
7. * must be valid.
8. *
9. * In the next sample, a vector holds shared_ptr to void. The first element is statically cast to shared_ptr<char>.
10. * The cast is valid as long as the source is not empty, regardless of whether the types are compatible or not.
11. *
12. * output:
13. * after creating the shared pointer
14. * -1 sp1 counter: 1
15. * after adding to the vector
16. * -2 sp1 counter: 2
17. * A
18. * after casting
19. * -3 sp1 counter: 3
20. * -4 spc counter: 3
21. */
22. int main()
23. {
24. std::vector<std::tr1::shared_ptr<void> > items;
25. std::tr1::shared_ptr<char> sp1(new char('A'));
26. std::tr1::shared_ptr<short> sp2(new short(66));
27. std::cout << "after creating the shared pointer" << std::endl;
28. std::cout << "-1 sp1 counter: " << sp1.use_count() << std::endl;
29. items.push_back(sp1);
30. items.push_back(sp2);
31. std::cout << "after adding to the vector" << std::endl;
32. std::cout << "-2 sp1 counter: " << sp1.use_count() << std::endl;
33. std::tr1::shared_ptr<char> spc = std::tr1::static_pointer_cast<char>(*(items.begin()));
34. if (spc)
35. std::cout << *spc << std::endl;
36. std::cout << "after casting" << std::endl;
37. std::cout << "-3 sp1 counter: " << sp1.use_count() << std::endl;
38. std::cout << "-4 spc counter: " << spc.use_count() << std::endl;
39.
40. return 0;
41. }
14.const cast,如果声明std::tr1::shared_ptr<const int> csp,可以声明std::tr1::shared_ptr<int> sp = std::tr1::const_pointer_cast<int>(csp);
1. #include <iostream>
2. #include <tr1/memory>
3.
4. /* To modify the value of the pointer object the const specifier must be removed. This is shown below.
5. *
6. * output:
7. * csp counter: 1
8. * 15
9. * 15
10. * csp counter: 2
11. * sp counter: 2
12. */
13. int main()
14. {
15. std::tr1::shared_ptr<const int> csp(new int(5));
16. std::cout << "csp counter: " << csp.use_count() << std::endl;
17.
18. std::tr1::shared_ptr<int> sp = std::tr1::const_pointer_cast<int>(csp);
19. *sp += 10;
20.
21. std::cout << *csp << std::endl;
22. std::cout << *sp << std::endl;
23.
24. std::cout << "csp counter: " << csp.use_count() << std::endl;
25. std::cout << "sp counter: " << sp.use_count() << std::endl;
26.
27. return 0;
28. }
15.weak_ptr的lock() 类似于shared_ptr的get()
1. #include <iostream>
2. #include <tr1/memory>
3.
4. /* The major weakness of shared_ptr is that it cannot detect cyclic dependencies. In this case, the reference counter is incremented
5. * more than it should actually be, so that the resources are no longer released when the shared pointer objects go out of scope.
6. * To fix this problem, a second smart pointer was created, weak_ptr, that points to a resource owned by a shared_ptr but does not
7. * affect the reference counter; it is a "weak reference." When the last shared_ptr that owns the resource referred by a weak_ptr,
8. * the resource is released and the weak pointer is marked as invalid. To check whether a weak_ptr is valid or not, you can use
9. * function expired() that returns true if the pointer was marked as invalid.
10. */
11.
12. /* Even though function get() (that provides direct access to the wrapped pointer) is available, it's not recommended to use it even
13. * in single-threaded applications. The safe alternative is function lock() that returns a shread_ptr sharing the resource pointed by
14. * the weak pointer.*/
15. void show(const std::tr1::weak_ptr<int>& wp)
16. {
17. std::tr1::shared_ptr<int> sp = wp.lock();
18. std::cout << *sp << std::endl;
19. }
20.
21. /*
22. * output:
23. * 44
24. * expired : true
25. */
26. int main()
27. {
28. std::tr1::weak_ptr<int> wp;
29. {
30. std::tr1::shared_ptr<int> sp(new int(44));
31. wp = sp;
32. show(wp);
33. }
34. std::cout << "expired : " << std::boolalpha << wp.expired() << std::endl;
35.
36. return 0;
37. }
16.一个使用shared_ptr和weak_ptr的二叉树数据结构示例
1. #include <iostream>
2. #include <tr1/memory>
3.
4. /* The following sample shows such a tree, but uses a weak_ptr to solve the cyclic dependency.*/
5. class Node
6. {
7. std::string value_;
8. std::tr1::shared_ptr<Node> left_;
9. std::tr1::shared_ptr<Node> right_;
10. std::tr1::weak_ptr<Node> parent_;
11.
12. public:
13. Node(const std::string value) :
14. value_(value)
15. {
16. }
17.
18. std::string Value() const
19. {
20. return value_;
21. }
22. std::tr1::shared_ptr<Node> Left() const
23. {
24. return left_;
25. }
26. std::tr1::shared_ptr<Node> Right() const
27. {
28. return right_;
29. }
30. std::tr1::weak_ptr<Node> Parent() const
31. {
32. return parent_;
33. }
34.
35. void SetParent(std::tr1::shared_ptr<Node> node)
36. {
37. parent_.reset();
38. parent_ = node;
39. }
40.
41. void SetLeft(std::tr1::shared_ptr<Node> node)
42. {
43. left_.reset();
44. left_ = node;
45. }
46.
47. void SetRight(std::tr1::shared_ptr<Node> node)
48. {
49. right_.reset();
50. right_ = node;
51. }
52. };
53.
54. std::string path(const std::tr1::shared_ptr<Node>& item)
55. {
56. std::tr1::weak_ptr<Node> wparent = item->Parent();
57. std::tr1::shared_ptr<Node> sparent = wparent.lock();
58.
59. if (sparent)
60. {
61. return path(sparent) + "//" + item->Value();
62. }
63.
64. return item->Value();
65. }
66.
67. /*
68. * output:
69. * C:/dir1/dir11
70. */
71. int main()
72. {
73. std::tr1::shared_ptr<Node> root(new Node("C:"));
74.
75. std::tr1::shared_ptr<Node> child1(new Node("dir1"));
76. std::tr1::shared_ptr<Node> child2(new Node("dir2"));
77.
78. root->SetLeft(child1);
79. child1->SetParent(root);
80.
81. root->SetRight(child2);
82. child2->SetParent(root);
83.
84. std::tr1::shared_ptr<Node> child11(new Node("dir11"));
85.
86. child1->SetLeft(child11);
87. child11->SetParent(child1);
88.
89. std::cout << "path: " << path(child11) << std::endl;
90.
91. return 0;
92. }
本文出自 “子 孑” 博客,请务必保留此出处http://zhangjunhd.blog.51cto.com/113473/148628