1、不能用一个原始地址初始化多个共享智能指针,会导致同一内存释放多次。
class Test { public: Test() { cout << "test的默认构造函数" << endl; } ~Test() { cout << "test的析构函数" << endl; } }; void test01() { Test *t = new Test; shared_ptr<Test>sp1(t); shared_ptr<Test>sp2(t); cout << "sp1的引用计数:" << sp1.use_count() << endl; cout << "sp2的引用计数:" << sp2.use_count() << endl; }
运行结果:
原因分析:
在这个例子中使用同一个指针 t 构造了两个智能指针对象 sp1 和 sp2,这二者之间是没有任何关系的,因为 sp2 并不是通过 sp1 初始化得到的实例对象。在离开作用域之后 指针t将被构造的两个智能指针各自析构,导致重复析构的错误。
2、在类里面返回一个管理这当前对象指针的智能指针对象,如下写法依然出现内存重复释放,原因和上面一样。
class A { public: A() { cout << "A的默认构造" << endl; } shared_ptr<A> getshareptr() { return shared_ptr<A>(this); } ~A() { cout << "A的析构函数" << endl; } }; void test03() { shared_ptr<A>sp1(new A); shared_ptr<A>sp2 = sp1->getshareptr(); cout << "sp1的引用计数:" << sp1.use_count() << endl; cout << "sp2的引用计数:" << sp2.use_count() << endl; }
使用weak_ptr改进版。使类继承于enable_shared_from_this
class A:public enable_shared_from_this<A> { public: A() { cout << "A的默认构造" << endl; } //在类里面返回一个管理这当前对象指针的智能指针对象 shared_ptr<A> getshareptr() { return shared_from_this();
//在这个函数内部使用weak_ptr调用lock()来返回一个shared_ptr对象 } ~A() { cout << "A的析构函数" << endl; } }; void test03() { // enable_shared_from_this类里面的weak_ptr也被初始化 shared_ptr<A>sp1(new A); shared_ptr<A>sp2 = sp1->getshareptr(); cout << "sp1的引用计数:" << sp1.use_count() << endl; cout<<"sp2的引用计数:<<sp2.use_count()<<endl; }
3、循环引用会导致内存泄漏。如下所示,A里面有个B类型的共享指针指针,B里面有个A类型的共享指针指针。初始化A类型的共享智能指针和B类型的共享智能指针,使A中B类型的共享指针指向B类型的共享智能指针,使B中A类型的共享指针指向A类型的共享智能指针。
1 class BB; 2 class AA 3 { 4 public: 5 shared_ptr<BB> bsp; 6 ~AA() 7 { 8 cout << "AA的析构函数" << endl; 9 } 10 }; 11 class BB 12 { 13 public: 14 shared_ptr<AA> asp; 15 ~BB() 16 { 17 cout << "BB的析构函数" << endl; 18 } 19 }; 20 void test04() 21 { 22 shared_ptr<AA> ap(new AA); 23 shared_ptr<BB> bp(new BB); 24 ap->bsp = bp; 25 bp->asp = ap; 26 cout << "A的引用计数:" << ap.use_count() << endl; 27 cout << "B的引用计数:" << bp.use_count() << endl; 28 29 }
运行结果:
发现没有打印析构函数,发生了内存泄漏。
解决办法:在第5行或者第14行把shared_ptr修改位weak_ptr,例如修改第5行
weak_ptr<BB> bsp;
运行结果:
这是由于bsp 是 weak_ptr 类型,打破了循环引用,这个赋值操作ap->bsp=bp并不会增加引用计数,所以 bp 的引用计数仍然为 1,在离开作用域之后 bp 的引用计数减为 0,类 B 的实例对象被析构。
在类 B 的实例对象被析构的时候,内部的 asp 也被析构,A内存的引用计数减为 1,当共享智能指针 ap 离开作用域之后,内存的引用计数减为 0,类 A 的实例对象被析构。