42 智能指针 auto_ptr, unique_ptr,shared_ptr,weak_ptr 整理

都是类模版

都不用开发者自己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 的生命周期。

有哪些坑点?

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/338862.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[足式机器人]Part3 机构运动学与动力学分析与建模 Ch00-3(2) 刚体的位形 Configuration of Rigid Body

本文仅供学习使用&#xff0c;总结很多本现有讲述运动学或动力学书籍后的总结&#xff0c;从矢量的角度进行分析&#xff0c;方法比较传统&#xff0c;但更易理解&#xff0c;并且现有的看似抽象方法&#xff0c;两者本质上并无不同。 2024年底本人学位论文发表后方可摘抄 若有…

TypeScript进阶(三)类型演算与高级内置类型

✨ 专栏介绍 TypeScript是一种由微软开发的开源编程语言&#xff0c;它是JavaScript的超集&#xff0c;意味着任何有效的JavaScript代码都是有效的TypeScript代码。TypeScript通过添加静态类型和其他特性来增强JavaScript&#xff0c;使其更适合大型项目和团队开发。 在TypeS…

最实用的 8 个免费 Android 数据恢复软件

如果您正在寻找最好的免费 Android 数据恢复软件&#xff0c;那就不用再犹豫了&#xff0c;因为我已经列出了最好的软件。不可否认&#xff0c;智能手机和平板电脑等 Android 设备正在与技术一起发展。与以前相比&#xff0c;它们也更加融入了我们的日常生活。 Android 智能手…

跟着小德学C++之进程信息记录

嗨&#xff0c;大家好&#xff0c;我是出生在达纳苏斯的一名德鲁伊&#xff0c;我是要立志成为海贼王&#xff0c;啊不&#xff0c;是立志成为科学家的德鲁伊。最近&#xff0c;我发现我们所处的世界是一个虚拟的世界&#xff0c;并由此开始&#xff0c;我展开了对我们这个世界…

掌握Java Future模式及其灵活应用

第1章&#xff1a;引言 大家好&#xff0c;我是小黑&#xff0c;今天咱们来聊聊Future。咱们程序员在日常工作中&#xff0c;肯定都遇到过需要处理耗时任务的情况&#xff0c;特别是在Java领域。比如说&#xff0c;小黑要从网络上下载数据&#xff0c;或者要执行一个计算密集型…

PPT插件-大珩助手-快速构建自己的图形

绘图板-快速构建自己的图形 通过手绘的方式&#xff0c;快速构建自己的想法和创意&#xff0c;通过在PPT中插入绘图&#xff0c;植入背景透明的绘图&#xff0c;点击画笔可切换橡皮擦&#xff0c;可以清空画板重新绘制。 素材库-存储图形 通过素材库存储自己的图形 图形调整…

干货|移动端App自动化之触屏操作自动化

工作中我们经常需要对应用的页面进行手势操作&#xff0c;比如滑动、长按、拖动等&#xff0c;AppiumDriver 为我们提供一个模拟手势操作的辅助类 TouchAction&#xff0c;可以通过它对手机屏幕进行手势操作。 具体用法参见链接&#xff1a;chromedriver下载地址与webview自动化…

“Tab“ 的新型可穿戴人工智能项链

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

【NVIDIA】Jetson Orin Nano系列:烧写Ubuntu22.04

1、简介 最新的sdk-manager已经可以安装到Ubuntu22.0&#xff0c;也支持在 Jetson Orin Nano 上烧写Ubuntu22.04。 官网介绍&#xff1a;https://developer.nvidia.com/sdk-manager 2、版本介绍 JetPack版本&#xff1a;https://developer.nvidia.com/embedded/jetpack-ar…

Golang,Gin框架使用ShouldBindJSON时出现EOF报错

前言 做毕设ing&#xff0c;使用的是Gin框架做的一个简单的管理系统。但偶尔也会碰到一些稀奇古怪的Bug&#xff0c;因此记录一下。 问题描述 api是这样写的 func UserRegisterHandler(c *gin.Context, user *usecase.UserOperate) {if err : c.ShouldBindJSON(&UserReg…

构建中国人自己的私人GPT

创作不易&#xff0c;请大家多鼓励支持。 在现实生活中&#xff0c;很多人的资料是不愿意公布在互联网上的&#xff0c;但是我们又要使用人工智能的能力帮我们处理文件、做决策、执行命令那怎么办呢&#xff1f;于是我们构建自己或公司的私人GPT变得非常重要。 先看效果 一、…

Word插件-大珩助手-手写电子签名

手写签名 支持鼠标写&#xff0c;支持触摸屏写&#xff0c;点击画笔按钮切换橡皮擦&#xff0c;支持清空画板重写&#xff0c;点击在word中插入签名&#xff0c;可插入背景透明的签字图 素材库-保存签名 将写好的签字图复制粘贴到素材库中&#xff0c;以便永久使用&#xff…