目录
上一节内容
share_ptr用法
share_ptr指针可以用于上一节所说的错误
例子(类定义)
主函数代码
执行的结果
解释说明
share_ptr 相关构造
空的share指针可以指向其他相同类型的变量来进行托管
[可以shared_ptr< T > sp2(new T())也可以shared_ptr< T > sp2(sp1)](<#可以shared_ptr< T > sp2(new T())也可以shared_ptr< T > sp2(sp1)>)
[shared_ptr sp4; 空的shared_ptr,指向类型为T[]的数组对象(C++17之后支持)[]>](<#shared_ptr<T[]> sp4; 空的shared_ptr,指向类型为T[]的数组对象(C++17之后支持)>)
[shared_ptr sp5(new T[] { … }); 指向类型为T的数组对象(C++17之后支持)[]>](<#shared_ptr<T[]> sp5(new T[] { … }); 指向类型为T的数组对象(C++17之后支持)>)
[shared_ptr< T > sp6(NULL, D()); //空的shared_ptr,接受一个D类型的删除器,使用D释放内存](<#shared_ptr< T > sp6(NULL, D()); //空的shared_ptr,接受一个D类型的删除器,使用D释放内存>)
[shared_ptr< T > sp7(new T(), D()); //定义shared_ptr,指向类型为T的对象,接受一个D类型的删除器,使用D删除器来释放内存](<#shared_ptr< T > sp7(new T(), D()); //定义shared_ptr,指向类型为T的对象,接受一个D类型的删除器,使用D删除器来释放内存>)
share_ptr初始化
share_ptr的构造函数
使用make_shared 初始化对象,分配内存效率更高(推荐使用)
赋值
主动释放
重置指针
交换指针的值
share_ptr使用陷阱
原因
解决办法之一
weak_ptr智能指针(弱指针)
weak智能指针的用法
注意
弱指针到共享指针的转化
特别感谢
上一节内容
C++智能指针(2/3)_木木em哈哈的博客-CSDN博客自动释放内存:智能指针使用了RAII(资源获取即初始化)的原则,在创建时分配内存,在销毁时自动释放内存,无需手动管理内存释放,避免了因为忘记释放内存而造成的内存泄漏问题。unique_ptr是一种独占所有权的智能指针,同一时间只能有一个unique_ptr指向一个对象,当unique_ptr被销毁时,对象也会被释放。在这之中开始时p1托管str的指针,后面p2接管str指针的同时会把p1的托管给取消,这样p1指针指向的就是NULL(空),从而报错。这是因为auto_ptr与unique_ptr的排他性。
https://blog.csdn.net/mumuemhaha/article/details/131689322?spm=1001.2014.3001.5502这一节我们来学最后的share_ptr和weak_ptr
share_ptr用法
shared_ptr使用引用计数的方式来管理资源,即每个shared_ptr对象都有一个关联的计数器,记录有多少个shared_ptr对象共享同一块内存资源。当计数器为0时,资源会被自动释放。
当复制或拷贝时,引用计数加1,当智能指针析构时,引用计数减1,如果计数为零,代表已经没有指针指向这块内存,那么我们就释放它!这就是 shared_ptr 采用的策略!
share_ptr指针可以用于上一节所说的错误

例子(类定义)
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| class Person { public: Person(int v) { this->no = v; cout << "构造函数 \t no = " << this->no << endl; }
~Person() { cout << "析构函数 \t no = " << this->no << endl; }
private: int no; };
|
主函数代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| int main() { shared_ptr<Person> sp1;
shared_ptr<Person> sp2(new Person(2));
cout << "sp1引用计数 = " << sp1.use_count() << endl; cout << "sp2引用计数 = " << sp2.use_count() << endl << endl;
sp1 = sp2; cout << "sp1引用计数 = " << sp1.use_count() << endl; cout << "sp2引用计数 = " << sp2.use_count() << endl << endl; shared_ptr<Person> sp3(sp1); cout << "sp1引用计数 = " << sp1.use_count() << endl; cout << "sp2引用计数 = " << sp2.use_count() << endl; cout << "sp2引用计数 = " << sp3.use_count() << endl << endl;
return 0; }
|
执行的结果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| 构造函数 no = 2 sp1引用计数 = 0 sp2引用计数 = 1
sp1引用计数 = 2 sp2引用计数 = 2
sp1引用计数 = 3 sp2引用计数 = 3 sp2引用计数 = 3
析构函数 no = 2
D:\C++\调试\x64\Debug\调试.exe (进程 1536)已退出,代码为 0。 要在调试停止时自动关闭控制台,请启用"工具"->"选项"->"调试"->"调试停止时自动关闭控制台"。 按任意键关闭此窗口. . .
|
解释说明
注释中说的很明白了,只要引用了share_ptr所指向的变量,他的引用计数就会加一
同时在函数中sp1,sp2,sp3共同管理一个share_ptr指针
share_ptr 相关构造
空的share指针可以指向其他相同类型的变量来进行托管
1 2 3
| shared_ptr<Person> sp1; Person *person_1 = new Person(1); sp1.reset(person_1);
|
可以shared_ptr< T > sp2(new T())也可以shared_ptr< T > sp2(sp1)
1 2
| shared_ptr<Person> sp2(new Person(2)); shared_ptr<Person> sp3(sp1);
|
shared_ptr<T[]> sp4; 空的shared_ptr,指向类型为T[]的数组对象(C++17之后支持)
1
| shared_ptr<Person[]> sp4;
|
shared_ptr<T[]> sp5(new T[] { … }); 指向类型为T的数组对象(C++17之后支持)
1
| shared_ptr<Person[]> sp5(new Person[5] { 1, 2, 3, 4, 5 });
|
创建一个有五个Person元素的数组分别为1,2,3,4,5也就是Person(1),Person(2)…
shared_ptr< T > sp6(NULL, D()); //空的shared_ptr,接受一个D类型的删除器,使用D释放内存
假设删除函数为
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| class Person { public: Person(int v) { this->no = v; cout << "构造函数 \t no = " << this->no << endl; }
~Person() { cout << "析构函数 \t no = " << this->no << endl; }
private: int no; };
class DestructPerson { public: void operator() (Person *pt) { cout << "DestructPerson..." << endl; delete pt; } };
|
则用法为
1
| shared_ptr<Person> sp6(NULL, DestructPerson());
|
shared_ptr< T > sp7(new T(), D()); //定义shared_ptr,指向类型为T的对象,接受一个D类型的删除器,使用D删除器来释放内存
1
| shared_ptr<Person> sp7(new Person(8), DestructPerson());
|
share_ptr初始化
share_ptr的构造函数
1 2
| shared_ptr<Person> up1(new Person(10)); shared_ptr<Person> up2(up1);
|
使用make_shared 初始化对象,分配内存效率更高(推荐使用)
1
| shared_ptr<Preson> up3 = make_shared<Preson>(2);
|
赋值
1 2 3
| shared_ptrr<int> up1(new int(10)); shared_ptr<int> up2(new int(11)); up1 = up2;
|
主动释放
1 2 3 4
| shared_ptrr<int> up1(new int(10)); up1 = nullptr ;
up1 = NULL;
|
重置指针
p.reset() ; 将p重置为空指针,所管理对象引用计数 减1
p.reset(p1); 将p重置为p1(的值),p 管控的对象计数减1,p接管对p1指针的管控
p.reset(p1,d); 将p重置为p1(的值),p 管控的对象计数减1并使用d作为删除器
p1是一个指针!
交换指针的值
1 2
| std::swap(p1,p2); p1.swap(p2);
|
share_ptr使用陷阱
小心因循环引用造成无法释放资源!
如下代码:
Boy类中有Girl的智能指针;
Girl类中有Boy的智能指针;
当他们交叉互相持有对方的管理对象时…(借用大佬写的代码)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
| #include <iostream> #include <string> #include <memory>
using namespace std;
class Girl;
class Boy { public: Boy() { cout << "Boy 构造函数" << endl; }
~Boy() { cout << "~Boy 析构函数" << endl; }
void setGirlFriend(shared_ptr<Girl> _girlFriend) { this->girlFriend = _girlFriend; }
private: shared_ptr<Girl> girlFriend; };
class Girl { public: Girl() { cout << "Girl 构造函数" << endl; }
~Girl() { cout << "~Girl 析构函数" << endl; }
void setBoyFriend(shared_ptr<Boy> _boyFriend) { this->boyFriend = _boyFriend; }
private: shared_ptr<Boy> boyFriend; };
void useTrap() { shared_ptr<Boy> spBoy(new Boy()); shared_ptr<Girl> spGirl(new Girl());
spBoy->setGirlFriend(spGirl); spGirl->setBoyFriend(spBoy); }
int main(void) { useTrap();
system("pause"); return 0; }
|
这里是一个boy里有个girl的指针,而girl里也有个boy的指针
到最后
1 2 3
| Boy 构造函数 Girl 构造函数 请按任意键继续. . .
|
空间都没有释放出来(没有析构函数)
原因

这里由于都各有对方的类,故引用计数为2
但是当程序结束的时候

函数中的智能指针清理掉了,但是类中嵌套的智能指针无法释放,所有类无法调用析构函数
解决办法之一
如果不用两个类中的指针互相关联,而是一方单方面获得管理对方的共享指针,这样可以正常释放
假设还是上面的那个例子
由于因为开始释放boy是引用次数为2,函数结束计数减一变为一
之后开始释放girl,girl引用次数为1,函数结束计数减一变为零
这是开始析构girl,同时就会把boy类也析构掉,计数再次减一
这是boy引用次数为零,则boy也开始析构了
1 2 3 4 5 6 7 8
| void useTrap() { shared_ptr<Boy> spBoy(new Boy()); shared_ptr<Girl> spGirl(new Girl());
spGirl->setBoyFriend(spBoy); }
|
weak_ptr智能指针(弱指针)
weak_ptr 设计的目的是为配合 shared_ptr 而引入的一种智能指针来协助 shared_ptr 工作, 它只可以从一个 shared_ptr 或另一个 weak_ptr 对象构造, 它的构造和析构不会引起引用记数的增加或减少。 同时weak_ptr 没有重载*和->但可以使用 lock 获得一个可用的 shared_ptr 对象。
weak智能指针的用法
weak_ptr的定义空指针(weak_ptr <T> a)和共享构造(weak_ptr <T> a(b)以及允许共享指针赋值给弱指针(a=b)都和其他智能指针差不多
同时和share_ptr一样可以用 .count()来查看引用次数
注意
弱指针不支持 * 和 -> 对指针的访问
弱指针到共享指针的转化
弱指针到共享指针的转化可以用.lock()来表示
例如
1 2 3 4 5
| shared_ptr<Girl> sp_girl; sp_girl = wpGirl_1.lock();
sp_girl = NULL;
|
上面share_ptr发生的问题的另一种解决办法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
| #include <iostream> #include <string> #include <memory>
using namespace std;
class Girl;
class Boy { public: Boy() { cout << "Boy 构造函数" << endl; }
~Boy() { cout << "~Boy 析构函数" << endl; }
void setGirlFriend(shared_ptr<Girl> _girlFriend) { this->girlFriend = _girlFriend;
shared_ptr<Girl> sp_girl; sp_girl = this->girlFriend.lock();
cout << sp_girl.use_count() << endl; sp_girl = NULL; }
private: weak_ptr<Girl> girlFriend; };
class Girl { public: Girl() { cout << "Girl 构造函数" << endl; }
~Girl() { cout << "~Girl 析构函数" << endl; }
void setBoyFriend(shared_ptr<Boy> _boyFriend) { this->boyFriend = _boyFriend; }
private: shared_ptr<Boy> boyFriend; };
void useTrap() { shared_ptr<Boy> spBoy(new Boy()); shared_ptr<Girl> spGirl(new Girl());
spBoy->setGirlFriend(spGirl); spGirl->setBoyFriend(spBoy); }
int main(void) { useTrap();
system("pause"); return 0; }
|
再次感谢大佬的代码
在这一串代码中主要变的就是各两个类中的对方函数的指针变为了弱指针(在需要的时候用.lock()给变回共享指针,使用完后置空)
这样就避免了双方都没有权限去析构对方类
特别感谢
(本章中用了不少这位大佬的代码,如有不妥,联系改正)
C++ 智能指针 - 全部用法详解_cpp智能指针特性_cpp_learners的博客-CSDN博客血的教训?不学智能指针,本人丢了一份工作。_cpp智能指针特性
https://blog.csdn.net/cpp_learner/article/details/118912592