都是类模版
都不用开发者自己delete 指针。这是因为智能指针有自己管理指向对象的能力,包括释放指向的内存,因此开发者不要自己释放。
auto_ptr, (废弃)C++98
已经被弃用,替代方案是unique_ptr.
被弃用的原因:
1.不能使用vector等容器保存auto_ptr
2.不能从函数中返回auto_ptr类型
//已经被弃用,替代方案是unique_ptr.
//
//被弃用的原因:
//
//1.不能使用vector等容器保存auto_ptr
//
//2.不能从函数中返回auto_ptr类型//3.在使用这样的code时,容易让开发者忘记,还有事情要做。void main(){cout << "....." << endl;auto_ptr<string> pstr(new string("abc"));auto_ptr<string> pstr1(pstr);//代码执行到这里, pstr1中是"abc",pstr变成了empty,if (pstr.get() ==nullptr) {cout << "pstr.get() == nullptr" << endl; //结果走到这一行}else {cout << "pstr.get() exsit " << endl;}//如果后面我们再次使用pstr就会有问题。cout << "断点在这里";}
unique_ptr, C11 (重点)
0、干啥的
独占式指针,意思是:同一个时间内,只有一个指针能够指向该指针。
当然,该对象的所有权还是可以移交出去的。
当这个unique_ptr被销毁的时候,指向的对象也会销毁。
在不指定删除器的情况下,大小和裸指针一样大。在指定了删除器的情况下,有可能比裸指针大。
如果删除器是 函数指针,则会变大
如果删除器是 lambda 表达式,则不会变大
1.如何实例化
2.常规操作--包括常用函数
3.指定删除器
shared_ptr,C11(重点)
0.内存图,大小为裸指针的2倍,多出来的第二个指针指向如下
1.共享所有权,可以被多个shared_ptr同时指向。
2.有额外的开销。
3.工作原理:使用了 引用计数,每个shared_ptr的拷贝都指向同样的内存。
所以,只有当最后一个指向该对象的shared_ptr指针不需要再指向该对象时候,那么这个shared_ptr才会去析构所指向的对象。
4.释放的时机有两种:
a.当最后一个shared_ptr指向其他对象的时候
b.当shared_ptr被析构的时候,比如说;在局部函数中,shared_ptr的作用域结束了,自然会被回收,紧跟着它指向的内存也会被释放
5. shared_ptr是类模型,且是explicit,不可以进行隐式类型的转换
6.初始化
shared_ptr<int> pi; // pi 是nullptr
shared_ptr<int> pi1(); // 注意这里:这不是定义一个shared_ptr<int> 变量, 这里:pi1()是函数声明。因此不会有build error。
void func130(shared_ptr<int> tempptr) {//引用计数变成4 tempptr = shared_ptr 100 [4 strong refs] [make_shared]cout << "xxx" << endl;
}shared_ptr<int> func131(shared_ptr<int>& temp) {return temp;
}void main(){shared_ptr<int> pi; // pi 是nullptr if (pi == nullptr) {cout << "pi == nullptr" << endl;}shared_ptr<int> pi1(); // 注意这里:这不是定义一个shared_ptr<int> 变量, 这里:pi1()是函数声明。因此不会有build error。//pi1 = make_shared<int>(100);//build error,pi1是函数声明。//由于shared_ptr是explicit的。因此要显示的实例化shared_ptr<int> pi2(new int);//pi2 = shared_ptr -842150451 [1 strong ref] [default] .........[ptr] = 0x000001f54ed67730 {-842150451}shared_ptr<int> pi3(new int());//pi3 = shared_ptr 0 [1 strong ref] [default].....[ptr] = 0x000001f54ed70bd0 {0}shared_ptr<int> pi4(new int(100));//pi4 = shared_ptr 100 [1 strong ref] [default]//让pi5 和 pi3指向同一块内存shared_ptr<int> pi5(pi3);// [ptr] = 0x000001f54ed70bd0 {0}//通过make_shared 实例化.//make_shared 是一个模版函数,//make_shared被认为是 安全,高效的。//make_shared生成的shared_ptr指针没有办法自定义删除器,//如下代码的意思是:通过 make_shared函数分配一块大小为int的空间,该空间的值是200,并用该空间的指针初始化 pi6shared_ptr<int> pi6(make_shared<int>(200));//打印结果cout << *pi6 << endl; //200//赋值pi = make_shared<int>(100);cout << *pi << endl;//100*pi6 = 999; //999cout << *pi6 << endl;//关于 shared_ptr的强引用指针的增加的例子。auto p6 = make_shared<int>(100); //强引用是1auto p7(p6);//强引用变成2auto p8(p7);//强引用变成3//当智能指针当做实参往函数里面传递的时候,强引用计数也会+1,但是当形参使用完毕后,又会减1func130(p7);//当func130方法执行完毕后,强引用又变回3//当函数返回值是智能指针时,计算器也会+1auto p9 = func131(p7); //强引用变成4//关于 shared_ptr的强引用指针的减少的例子。p9 = nullptr;//强引用变成3p8 = make_shared<int>(200);//强引用变成2, p8的指向变化的时候,也会-1cout << "断点在这里";
}
6.1 初始化数组 C++17
//使用shared_ptr管理动态数组:shared_ptr<int[]> str7111(new int[3]());//new int[3]()带小括号,这三个int的值默认都会给0shared_ptr<int[]> str7(new int[3]);for (int i = 0; i < 3;i++) {str7[i] = i*3 + 6;}for (int i = 0; i < 3; i++) {cout << "str7[" << i<<"] = " <<str7[i]<< endl;}int aaaaaa = str7.use_count();//count 是 1shared_ptr<Teacher121[]> str8(new Teacher121[3]());//new Teacher121[3]()带小括号,不会给三个Teacher121赋任何值shared_ptr<Teacher121[]> str9(new Teacher121[3]);str8[0] = Teacher121(20);str8[1] = Teacher121(30);str8[2] = Teacher121(40);cout << "--------" << endl;for (int i = 0; i < 3;i++) {str8[i].print();}cout << "--------" << endl;str9[0] = Teacher121(200);str9[1] = Teacher121(300);str9[2] = Teacher121(400);cout << "--------" << endl;for (int i = 0; i < 3; i++) {str9[i].print();}cout << "--------" << endl;
6.2 初始化数组 C++17之前,这个要结合删除器,在 删除器的时候会一并介绍,
7.相关函数
long use_count
返回管理当前对象的不同 shared_ptr
实例(包含 this )数量。若无管理对象,则返回 0 。
多线程环境下, use_count 返回的值是近似的(典型实现使用 memory_order_relaxed 加载)
std::shared_ptr<T>::use_countlong use_count() const noexcept;返回管理当前对象的不同 shared_ptr 实例(包含 this )数量。若无管理对象,则返回 0 。多线程环境下, use_count 返回的值是近似的(典型实现使用 memory_order_relaxed 加载)参数(无)返回值管理当前对象的 shared_ptr 实例数量,或若无被管理对象则为 0 。注意常用使用包括
◦与 0 比较。若 use_count 返回零,则智能指针为空且不管理对象(无论被存储指针是否为空)。多线程环境下,这不隐含被管理对象的析构函数已完成。
◦与 1 比较。若 use_count 返回 1 ,则无其他拥有者。(被弃用成员函数 unique() 为此使用情况提供。)多线程环境中,这不隐含对象可以安全修改,因为先前拥有者对被管理对象的访问可能未完成,而因为新的共享拥有者可以同时引入,例如用 std::weak_ptr::lock 。
//关于 shared_ptr的强引用指针的增加的例子。auto p6 = make_shared<int>(100); //强引用是1auto p7(p6);//强引用变成2auto p8(p7);//强引用变成3//当智能指针当做实参往函数里面传递的时候,强引用计数也会+1,但是当形参使用完毕后,又会减1func130(p7);//当func130方法执行完毕后,强引用又变回3//当函数返回值是智能指针时,计算器也会+1auto p9 = func131(p7); //强引用变成4//关于 shared_ptr的强引用指针的减少的例子。p9 = nullptr;//强引用变成3p8 = make_shared<int>(200);//强引用变成2, p8的指向变化的时候,也会-1int count = p6.use_count();//返回2
bool unique()
std::shared_ptr<T>::uniquebool unique() const noexcept;(C++17 中弃用)
(C++20 中移除) 检查 *this 是否管理当前对象的仅有 shared_ptr 实例,即是否 use_count() == 1 。参数(无)返回值若 *this 否管理当前对象的仅有 shared_ptr 实例则为 true ,否则为 false 。注意此函数于 C++17 中被弃用并于 C++20 中移除,因为 use_count 在多线程环境中只是估计(见 use_count 中的“注意”)。
std::shared_ptr<T>::reset
如果reset()括号中没有参数,则 ptr==nullptr.这意味着,如果ptr是唯一的指向内存的指针,则内存会被释放。如果有多个指针指向该内存,则 强引用-1.
如果reset(Y* newptr)括号中有参数,会将ptr的指向 newptr 的内存。如果ptr是唯一的之前的指向内存的指针,则内存会被释放。如果有多个指针指向该内存,则 强引用-1.
std::shared_ptr<T>::resetvoid reset() noexcept;(1) (C++11 起) template< class Y >
void reset( Y* ptr );(2) (C++11 起) template< class Y, class Deleter >
void reset( Y* ptr, Deleter d );(3) (C++11 起) template< class Y, class Deleter, class Alloc >
void reset( Y* ptr, Deleter d, Alloc alloc );(4) (C++11 起) 以 ptr 所指向的对象替换被管理对象。能可选地提供删除器 d ,之后在无 shared_ptr 对象占有该对象时以之销毁新对象。默认以 delete 表达式为删除器。始终选择对应提供类型的 delete 表达式,这是函数以使用分离的形参 Y 的模板实现的理由。若 *this 已占有对象,且它是最后一个占有该对象的 shared_ptr ,则通过所占有的删除器销毁对象。若 ptr 所指向的对象已被占有,则函数通常会导致未定义行为。1) 释放被管理对象的所有权,若存在。调用后, *this 不管理对象。等价于 shared_ptr().swap(*this); 。2-4) 以 ptr 所指向对象替换被管理对象。 Y 必须是完整类型且可隐式转换为 T 。另外:2) 以 delete 表达式为删除器。合法的 delete 表达式必须可用,即 delete ptr 必须为良式,拥有良好定义行为且不抛任何异常。等价于 shared_ptr<T>(ptr).swap(*this); 。3) 以指定的删除器 d 为删除器。 Deleter 必须对 T 类型可调用,即 d(ptr)必须为良构,拥有良好定义行为且不抛任何异常。 Deleter 必须可复制构造 (CopyConstructible) ,且其复制构造函数和析构函数必须不抛异常。等价于 shared_ptr<T>(ptr, d).swap(*this); 。4) 同 (3) ,但额外地用 alloc 的副本分配内部使用的数据。 Alloc 必须是分配器 (Allocator) 。复制构造函数和析构函数必须不抛异常。等价于 shared_ptr<T>(ptr, d, alloc).swap(*this); 。参数ptr - 指向要取得所有权的对象的指针
d - 为删除对象而存储的删除器
alloc - 内部存储所用的分配器 返回值(无)异常2) 若无法获得要求的额外内存则为 std::bad_alloc 。可能因其他错误抛出实现定义的异常。若出现异常则调用 delete ptr 。3-4) 若无法获得要求的额外内存则为 std::bad_alloc 。可能因其他错误抛出实现定义的异常。若出现异常则调用 d(ptr) 。
//reset函数,没有参数shared_ptr<string> str1(new string("abc"));shared_ptr<string> str2 = str1;// str1 和 str2都指向“abc”这块内存,强引用数量2str1.reset();//这时候 str1变成nullptr,指向“abc”这块内存的强引用数量变成1str2.reset();// 这时候 str2变成nullptr,指向“abc”这块内存的强引用数量变成0,于是这块内存被释放shared_ptr<string> str3(new string("def"));shared_ptr<string> str4(str3);// str3 和 str4都指向“def”这块内存,强引用数量2str4.reset(new string("iou")); //str4指向新的内存,str3指向的内存的 强引用变成1,str4的强引用变成1,不过str4指向另一个内存空间了//str3 [ptr] = 0x00000237028fbc30 "def"//strs4 [ptr] = 0x00000237028fba00 "iou"
std::shared_ptr<T>::get
返回存储的指针。
注意,返回的存储的指针,我们也叫做裸指针,
由于这个裸指针还是依赖于 shared_ptr存在,因此程序员不要手动的delete 它,如果delete了,那么shared_ptr在释放这块内存的时候,delete的时候,这块指向的空间会被delete两次,就会造成程序异常。
std::shared_ptr<T>::getT* get() const noexcept;(C++17 前) element_type* get() const noexcept;(C++17 起) 返回存储的指针。参数(无)返回值存储的指针。注意shared_ptr 可能在存储指向一个对象的指针时共享另一对象的所有权。 get() 返回存储的指针,而非被管理指针。
shared_ptr<string> str6(new string("qqq"));string * s = str6.get();cout << "s = " << s << " *s = " << *s << endl;//delete s;//程序员不要手动的delete,否则会运行时异常。*s = "www";cout << "s = " << s << " *s = " << *s << endl;//那么get()方法的应用场景主要是为了第三方库,很大程度上第三方库的参数可能是 裸指针,而不是智能指针
std::shared_ptr<T>::swap 这玩意不常用,这里就不举例了
std::shared_ptr<T>::swapvoid swap( shared_ptr& r ) noexcept;(C++11 起) 交换 *this 与 r 的存储指针值与所有权。不调整引用计数,若它们存在。参数r - 要与之交换内容的智能指针 返回值(无)
8. 指定删除器
从前面的知识中知道,在使用智能指针的时候,我们不需要手动的delete,那么C++编译器是如何自动的delete的呢?这里就引出了 删除器 的概念。
1.为什么要自己指定删除器呢?在C++17之前shared_ptr如果管理的是动态数组,则需要自己指定删除器。
实际上C++17之前 shared_ptr内部就是 使用关键字 delete ptr完成的。也正是由于由于shared_ptr 内部只有delete ptr,没有delete[] ptr,因此在C++17之前 如果shared_ptr管理的是动态数组,那么就需要自己指定删除器。
如果知道是C++17之前不支持呢?
参考C++ 文档:shared_ptr中的关于[]的介绍
operator[] (C++17) | 提供到被存储数组的带下标访问 (公开成员函数) |
2.什么是 删除器
a.删除器可以是一个函数,返回值是void,参数是( T * p);
class Teacher122 {public:Teacher122() {cout << "Teacher122 没有参数的构造函数被执行 " << this << endl;}Teacher122(int age) :m_age(age) {cout << "Teacher122 int age 构造函数被执行 " << this<< endl;}void print() {cout << "age = " << this->m_age << " " << this << endl;}~Teacher122() {cout << "Teacher122 析构函数被调用 " << this << endl;}void setAge(int age) {this->m_age = age;}
private:int m_age;
};void mydelete(int *p) {cout << "mydelete int called" << endl;delete p;p = nullptr;
}void mydeletearr(int *p) {cout << "mydeletearr int called" << endl;delete [] p;p = nullptr;
}void mydeleteTeacher122(Teacher122 *p) {cout << "mydeleteTeacher122 called" << endl;delete[] p;p = nullptr;
}void main() {//C++17之前 shared_ptr管理 普通 怎么写shared_ptr<int> intptr(new int(200),mydelete);intptr = nullptr;cout << "-----------" << endl;//C++17之前 shared_ptr管理 数组怎么写?由于没有下标[]可以操作,因此,只能通过get得到裸指针,然后通过裸指针操作数据shared_ptr<int> intarrptr(new int[3], mydeletearr);for (int i = 0; i < 3;i++) {//注意,要获得数据,只能通过get()方法得到裸指针,该裸指针肯定是指向int的,因此每次加1都是跳4个字节,因此可以通过 *(ptr + i)给数据赋值。*(intarrptr.get()+i) = 9 * i;}for (size_t i = 0; i < 3; i++){cout << "*(intarrptr.get()+i = " << *(intarrptr.get() + i) << endl;}intarrptr = nullptr;//结果://*(intarrptr.get()+i = 0//*(intarrptr.get() + i = 9//* (intarrptr.get() + i = 18//mydeletearr int calledC++17之前 shared_ptr管理 普通类 怎么写shared_ptr<Teacher122> pteacher1(new Teacher122());pteacher1->print();pteacher1->setAge(78);pteacher1->print();cout << "mmm" << endl;pteacher1 = nullptr;//Teacher122 没有参数的构造函数被执行 00000130B9427730// age = -842150451 00000130B9427730// age = 78 00000130B9427730// mmm// Teacher122 析构函数被调用 00000130B9427730C++17之前 shared_ptr管理 普通类数组 怎么写shared_ptr<Teacher122> pteacherarr(new Teacher122[3], mydeleteTeacher122);for (int i = 0; i < 3;i++) {//get()函数返回裸指针Teacher122* temp = pteacherarr.get() + i;temp->setAge((i + 1) * 30);}for (int i = 0; i < 3; i++) {Teacher122* temp = pteacherarr.get() + i;temp->print();}//Teacher122 没有参数的构造函数被执行 00000130B94322F8// Teacher122 没有参数的构造函数被执行 00000130B94322FC// Teacher122 没有参数的构造函数被执行 00000130B9432300// age = 30 00000130B94322F8// age = 60 00000130B94322FC// age = 90 00000130B9432300// mydeleteTeacher122 called// Teacher122 析构函数被调用 00000130B9432300// Teacher122 析构函数被调用 00000130B94322FC// Teacher122 析构函数被调用 00000130B94322F8}
b.删除器可以是一个lambda表达式
//b.删除器可以是一个lambda表达式cout << "删除器是一个lambda表达式start " << endl;shared_ptr<Teacher122> pteacherarr2(new Teacher122[3], [](Teacher122 *p) {delete[] p;p = nullptr;});for (int i = 0; i < 3; i++) {//get()函数返回裸指针Teacher122* temp = pteacherarr2.get() + i;temp->setAge((i + 1) * 50);}for (int i = 0; i < 3; i++) {Teacher122* temp = pteacherarr2.get() + i;temp->print();}cout << "删除器是一个lambda表达式end " << endl;//删除器是一个lambda表达式start// Teacher122 没有参数的构造函数被执行 0000025294FC1D58// Teacher122 没有参数的构造函数被执行 0000025294FC1D5C// Teacher122 没有参数的构造函数被执行 0000025294FC1D60// age = 50 0000025294FC1D58// age = 100 0000025294FC1D5C// age = 150 0000025294FC1D60// 删除器是一个lambda表达式end// Teacher122 析构函数被调用 0000025294FC1D60// Teacher122 析构函数被调用 0000025294FC1D5C// Teacher122 析构函数被调用 0000025294FC1D58
c.可用default_delete来做删除器。
default_delete是标准库里的模板类
cout << "删除器是一个default_delete 标准库模版 start " << endl;shared_ptr<Teacher122> pteacherarr3(new Teacher122[3], default_delete<Teacher122[]>());for (int i = 0; i < 3; i++) {//get()函数返回裸指针Teacher122* temp = pteacherarr3.get() + i;temp->setAge((i + 1) * 60);}for (int i = 0; i < 3; i++) {Teacher122* temp = pteacherarr3.get() + i;temp->print();}cout << "删除器是一个default_delete 标准库模版 end " << endl;//删除器是一个default_delete 标准库模版 start// Teacher122 没有参数的构造函数被执行 000001CD1E9D2488// Teacher122 没有参数的构造函数被执行 000001CD1E9D248C// Teacher122 没有参数的构造函数被执行 000001CD1E9D2490// age = 60 000001CD1E9D2488// age = 120 000001CD1E9D248C// age = 180 000001CD1E9D2490// 删除器是一个default_delete 标准库模版 end// Teacher122 析构函数被调用 000001CD1E9D2490// Teacher122 析构函数被调用 000001CD1E9D248C// Teacher122 析构函数被调用 000001CD1E9D2488
d.make_shared无法指定删除器,只能使用默认的,因此动态生成数组不能使用make_shared
3.注意的是C++17之后shared_ptr已经可以直接管理动态数组了
写法如下,
//使用shared_ptr管理动态数组:shared_ptr<int[]> str7111(new int[3]());//new int[3]()带小括号,这三个int的值默认都会给0shared_ptr<int[]> str7(new int[3]);for (int i = 0; i < 3;i++) {str7[i] = i*3 + 6;}for (int i = 0; i < 3; i++) {cout << "str7[" << i<<"] = " <<str7[i]<< endl;}int aaaaaa = str7.use_count();//count 是 1shared_ptr<Teacher121[]> str8(new Teacher121[3]());//new Teacher121[3]()带小括号,不会给三个Teacher121赋任何值shared_ptr<Teacher121[]> str9(new Teacher121[3]);str8[0] = Teacher121(20);str8[1] = Teacher121(30);str8[2] = Teacher121(40);cout << "--------" << endl;for (int i = 0; i < 3;i++) {str8[i].print();}cout << "--------" << endl;str9[0] = Teacher121(200);str9[1] = Teacher121(300);str9[2] = Teacher121(400);cout << "--------" << endl;for (int i = 0; i < 3; i++) {str9[i].print();}cout << "--------" << endl;
9.shared_ptr的使用陷阱
a.当返回值是 shared_ptr的时候,要注意是不是有变量接受。
//9.shared_ptr的使用陷阱
//a.当返回值是 shared_ptr 的时候,要注意是不是有变量接受。
//如果没有变量接受,那么离开 func135方法的作用域后,shared_ptr 就会销毁
//如果有变量接受,则shared_ptr的强引用+1
shared_ptr<int> func135() {return make_shared<int>(199);
}
void main() {func135();cout << "duandian 1" << endl;shared_ptr<int> aa = func135();//aa = shared_ptr 199 [1 strong ref] [make_shared]cout << "duandian 2" << endl;
}
b.慎用裸指针
最好不要 让 裸指针和智能指针混用。
b1如果混用,注意:一个裸指针只能初始化一个shared_ptr,
一旦让一个裸指针初始化了多个shared_ptr.
当ptr1销毁的时候,裸指针也会销毁。但是ptr2还是指向的裸指针,就会有问题。
b2,一旦裸指针初始化了智能指针,就不要去delete 裸指针了。
b3, 裸指针作为临时对象shared_ptr的初始化参数,在临时对象shared_ptr销毁的时候,裸指针也会被释放。
b4. shared_ptr通过get方法获得的指针不要绑定在其他的指针上,也不要delete
void fun136(shared_ptr<int> tempptr){cout << "fun136 called" << endl;
}void main() {//b.慎用裸指针// 最好不要 让 裸指针和智能指针混用。// b1如果混用, 注意:一个裸指针只能初始化一个shared_ptr,// 一旦让一个裸指针初始化了多个shared_ptr.// 当ptr1销毁的时候,裸指针也会销毁。但是ptr2还是指向的裸指针,就会有问题。int *p = new int(100);shared_ptr<int> ptr1(p);//shared_ptr<int> ptr2(p);//让裸指针p初始化了2个shared_ptr,一旦运行,就run time exception// b2,一旦裸指针初始化了智能指针,这个裸指针的生命管理就交给智能指针了,就不要去delete 裸指针了。int *p2 = new int(200);shared_ptr<int> ptr3(p2);//delete p2;//手动delete,就会有run time exception// b3, 裸指针作为临时对象shared_ptr的初始化参数,在临时对象shared_ptr销毁的时候,裸指针也会被释放。int *p3 = new int(300);fun136(shared_ptr<int>(p3));cout << "duandian" << endl;//由于 临时变量 shared_ptr<int>(p3) 传递到 fun136方法的时候,强引用计数不会+1,因此当func136执行完毕后,引用计数-1变成0,临时便令shared_ptr<int>(p3)会被销毁,进而裸指针p也会被delete//注意这里p3已经被释放了,就不要再用了// b4.shared_ptr通过get方法获得的指针不要绑定在其他的指针上,也不要deleteshared_ptr<int> p5(new int(500));shared_ptr<int> p6(make_shared<int>(600));int * pp5 = p5.get();cout << "duandian 2 " << endl;//shared_ptr<int> p7(pp5);//这里不能将裸指针 pp5 绑定到其他 智能指针上了//delete pp5;//也不要delete 裸指针
}
b5.不要把类对象this 做为shared_ptr的参数
//不要把类对象this 做为shared_ptr的参数,这其实很好理解。
//假设被人调用了,那么this这个裸指针 就被两个不同的 shared_ptr指向了。
//class Teacher136 {
//public:
// shared_ptr<Teacher136> getTeacher136() {
// return shared_ptr<Teacher136>(this);
// }
//};//上述问题如何解决呢?
//让 Teacher136 继承enable_shared_from_this<Teacher137>.
//返回shared_from_this();class Teacher137 :public enable_shared_from_this<Teacher137>{
public:shared_ptr<Teacher137> getTeacher137() {return shared_from_this();}int mage;
};void main() {//Teacher137 tea;//tea.mage = 10;//注意使用,因为返回的shared_from_this(),那么意味着之前一定是要有 智能指针指向这个this的,因此要先弄出来一个智能指针Teacher137 *pt = new Teacher137();shared_ptr<Teacher137> ptea(pt);shared_ptr<Teacher137> ptea1 = ptea->getTeacher137();ptea->mage = 90;cout << pt->mage << " " << ptea1->mage << endl;
}
10.移动语义也使用于智能指针
shared_ptr<int> p1(make_shared<int>(100));
shared_ptr<int> p2 = move(p1);
//10.移动语义也使用于智能指针shared_ptr<int> p1(make_shared<int>(100));shared_ptr<int> p2 = move(p1);// 从测试结果看: p1变成empty 了,p2变成指向 100的那块内存了,// 这说明shared_ptr类中对于移动构造的实现是:转移裸指针的所属,并将强引用那块的指针也转移了cout << " " << endl;
11.使用建议: 优先使用 make_shared<T>(200),make_shared被认为是安全的,效率高的。
weak_ptr C11(辅助shared_ptr)
是个啥?
类模版
用来辅助shared_ptr进行工作的。
shared_ptr 和 weak_ptr 所指向对象的引用计数,有两种,一种是强引用,一种是弱引用。
强引用指的是 shared_ptr指向的个数
弱引用指的是 weak_ptr指向的个数。
weak_ptr指向一个由shared_ptr管理的对象。
当shard_ptr指向的对象的强引用 计数变成0的时候,该对象会析构,这时候是不用看 weak_ptr的弱引用计数的。
weak_ptr 不能独立存在,必须要依附于shard_ptr存在。
有啥用?
weak_ptr 监视 shard_ptr 的生命周期用的,是对shard_ptr的一种扩展。
通过 use_count(); 可以获取强引用的计数
通过 expired(); 是否过期,如use_count()返回0,则返回true。
如上两个函数给人的感觉好像重复了, 只是多了一个判断?查了下 C++的文档,好像也没有特殊的地方。有知道的小伙伴可以帮忙回复一下。
通过 reset();可以将自己的这个弱引用==nullptr,弱引用计数-1
lock();检查weak_ptr 指向的对象是否存在,如存在,返回一个指向该对象的 shared_ptr(这时候对象的强引用计数就会+1)
怎么用?
void main() {shared_ptr<string> str1(new string("abc"));weak_ptr<string> wstr2(str1);cout << wstr2.use_count() << endl;//1,use_count()可以获取强引用的计数shared_ptr<string> str2(str1);shared_ptr<string> str3(str1);cout << wstr2.use_count() << endl;//3,use_count()可以获取强引用的计数cout << "---------------" << endl;auto str5 = make_shared<string>("def");weak_ptr<string> wstr6(str5);weak_ptr<string> wstr7(str5);weak_ptr<string> wstr8;wstr8 = wstr7;//wstr8 = weak_ptr "def" [1 strong ref, 3 weak refs] [make_shared]wstr8.reset();// 当wstr8 reset之后,str8为empty//str7的值是: wstr7 = weak_ptr "def"[1 strong ref, 2 weak refs][make_shared]cout << "......" << endl;//lock的使用if (!wstr7.expired()) {shared_ptr<string> wstr10 = wstr7.lock();if (wstr10 != nullptr) {cout << wstr7.use_count() << endl; // wstr7 = weak_ptr "def" [2 strong ref, 2 weak refs] [make_shared]}}cout << wstr7.use_count() << endl; // 出了作用域后,wstr10的强引用会被-1. 因此wstr7 = weak_ptr "def" [1 strong ref, 2 weak refs] [make_shared]
}
使用场景?
监视 shard_ptr 的生命周期。