先看一个例子:
#include <stdio.h> #include <iostream> #include <memory> using namespace std; class A { public: A() { printf("A constructor\n"); } ~A() { printf("A destructor\n"); } void Print() { printf("This is A\n"); } }; int _tmain(int argc, _TCHAR* argv[]) { shared_ptr<A> a(new A()); shared_ptr<A> b(new A()); a = b; getchar(); return 0; }
A constructor A constructor A destructor上面的例子中创建了共享指针a和b,引用计数都是1,b赋值给a,此时a最初所指对象会被销毁,因为它的引用计数变为0,b所指的对象引用计数加1
另一个例子:
#include <stdio.h> #include <iostream> #include <memory> #include <vector> using namespace std; class A { public: A() { printf("A constructor\n"); } ~A() { printf("A destructor\n"); } void Print() { printf("This is A\n"); } }; void SP() { A* p = new A(); shared_ptr<A> a(p); shared_ptr<A> b(p); printf("a.use_count(): %d, b.use_count(): %d\n", a.use_count(), b.use_count()); } int _tmain(int argc, _TCHAR* argv[]) { SP(); getchar(); return 0; }
A constructor a.use_count(): 1, b.use_count(): 1 A destructor A destructor
可以看出,a和b都关联到了p上,并且a和b的引用计数也是单独算的,都是1,这就导致函数退出的时候把p指向的对象销毁了两次,导致错误发生。
接着看例子:
#include <stdio.h> #include <iostream> #include <memory> #include <vector> using namespace std; class A { public: A() { printf("A constructor\n"); } ~A() { printf("A destructor\n"); } void Print() { printf("This is A\n"); } }; int _tmain(int argc, _TCHAR* argv[]) { shared_ptr<A> a(new A()); A* p = a.get(); p->Print(); printf("a.use_count(): %d\n", a.use_count()); getchar(); return 0; }
A constructor This is A a.use_count(): 1
接下来的例子:
#include <stdio.h> #include <iostream> #include <memory> #include <vector> using namespace std; class A { public: A() { printf("A constructor\n"); } ~A() { printf("A destructor\n"); } void Print() { printf("This is A\n"); } }; int _tmain(int argc, _TCHAR* argv[]) { shared_ptr<A> a(new A()); shared_ptr<A> b(a); shared_ptr<A> c(b); printf("a.use_count(): %d\n", a.use_count()); printf("b.use_count(): %d\n", b.use_count()); printf("c.use_count(): %d\n", c.use_count()); a.reset(); printf("\nAfter a.reset()\n"); printf("a.use_count(): %d\n", a.use_count()); printf("b.use_count(): %d\n", b.use_count()); printf("c.use_count(): %d\n", c.use_count()); getchar(); return 0; }
A constructor a.use_count(): 3 b.use_count(): 3 c.use_count(): 3 After a.reset() a.use_count(): 0 b.use_count(): 2 c.use_count(): 2
调用reset后,a就不再跟之前绑定的指针有任何关系了(实际过程是a的内部成员变量_Ptr和_Rep都被置为0,通过创建临时变量再Swap),所以引用b和c的引用计数也都相应减1
make_shared的使用:
#include <stdio.h> #include <iostream> #include <memory> #include <vector> using namespace std; class A { public: A() { printf("A constructor\n"); } A(int a): m_a(a) { printf("A constructor param\n"); } ~A() { printf("A destructor\n"); } void Print() { printf("This is A\n"); } int m_a; }; int _tmain(int argc, _TCHAR* argv[]) { shared_ptr<A> d = make_shared<A>(); shared_ptr<A> e = make_shared<A>(1); d->Print(); e->Print(); getchar(); return 0; }
A constructor A constructor param This is A This is A
A: 为了节省一次内存分配,原来 shared_ptr<A> x(new A); 需要为 A 和 ref_count 各分配一次内存,现在用 make_shared() 的话,可以一次分配一块足够大的内存,供 A 和 ref_count 对象容身。不过 A 的构造函数参数要传给 make_shared(),后者再传给 A::A()。
shared_ptr有两种类型转换函数,一个是static_pointer_cast, 一个是dynamic_pointer_cast,用法和static_cast和dynamic_cast很像。
看如下例子:
#include <stdio.h> #include <memory> using namespace std; class A { public: A() { printf("A constructor\n"); } ~A() { printf("A destructor\n"); } virtual void VFun() {} }; class B: public A { public: B() { printf("B constructor\n"); } ~B() { printf("B destructor\n"); } void VFun() {} }; int _tmain(int argc, _TCHAR* argv[]) { shared_ptr<A> a = shared_ptr<B>(new B()); printf("a.get(): %p\n\n", a.get()); shared_ptr<B> b = dynamic_pointer_cast<B>(shared_ptr<A>(new A())); printf("b.get(): %p\n\n", b.get()); shared_ptr<B> c = dynamic_pointer_cast<B>(a); printf("c.get(): %p\n\n", c.get()); getchar(); return 0; }
A constructor B constructor a.get(): 0066AEE8 A constructor A destructor b.get(): 00000000 c.get(): 0066AEE8
dynamic_pointer_cast下行转换基类必须有虚函数成员
#include <stdio.h> #include <memory> using namespace std; class A { public: A() { printf("A constructor\n"); } ~A() { printf("A destructor\n"); } }; class B: public A { public: B() { printf("B constructor\n"); } ~B() { printf("B destructor\n"); } }; int _tmain(int argc, _TCHAR* argv[]) { shared_ptr<B> b = static_pointer_cast<B>(shared_ptr<A>(new A())); printf("b.get(): %p\n", b.get()); b.reset(); printf("\n"); shared_ptr<A> a = static_pointer_cast<A>(shared_ptr<B>(new B())); printf("a.get(): %p\n", a.get()); a.reset(); getchar(); return 0; }
A constructor b.get(): 0049AEE8 A destructor A constructor B constructor a.get(): 0049AEE8 B destructor A destructor