一 智能指针
1.1 手动初始化
注意:share_ptr p = new int(10); //错误 share_ptr是explicit,不能进行隐式类型转换,只能直接初始化
1.1.1 make_shared
//功能:在堆区可以动态分配对象,并返回一个share_ptr(推荐,安全,高效)(构造方法初始化) auto p = std::make_shared<string>("helloworld"); shared_ptr<int> p1 = make_shared<int>(5); cout << *p1 << endl; shared_ptr<string> ps = make_shared<string>("hello world"); cout << *ps << endl; //手动初始化和使用make_shared函数模板初始化有什么区别? //开销小,效率高(数据和引用计数存在同一个空间) //构造函数初始化:数据和引用计数不再同一段空间,需要间接访问 shared_ptr<A> a1 = make_shared<A>(); shared_ptr<A> a2(a1);
1.2 常规操作
1.2.1 use_count()
功能:返回有多少个智能指针指向某个对象(引用计数的个数) 用途:主要用于调试
shared_ptr<A> a1 = make_shared<A>(); shared_ptr<A> a2(a1); cout << a2.use_count() << endl; //返回当前有多少个指针指向当前对象或者空间
1.2.2 unique();
功能:是否该智能指针独占某个对象,独占返回true,否则返回false;
if (a1.unique()) //判断当前指针是否独享(只有它自己指向该对象)或者空间 { cout << "a1 is unique ptr" << endl; }
1.2.3 reset
功能:判断当前指针是否独享该对象,如果独享,则释放该对象,否则将该指针置为NULL,并将引用计数器减一 用法:reset()或者reset(参数)
//判断当前指针是否独享该对象,如果独享,则释放该对象,并使该指针指向形参所对应的空间 a1.reset(new A(10)); //shared_ptr<A> pa(new A(188)); //a1.reset(pa); cout << a1->m_a << endl;
1.2.4 解引用
获取智能指针指向的对象,并对其操作 get(); //获取智能指针中保存的裸指针。
shared_ptr<int> pd = make_shared<int>(5); Test(pd.get());
1.2.5 指定删除器
功能:有些情况,默认删除器处理不了(share_ptr管理的动态数组) 需要我们自己指定删除器,调用删除器函数释放空间
//指定删除器:当删除器不起作用的时候,需要自己指定删除器 void(*)(T*) //shared_ptr<A> pa(new A[3]); //delete pa --->应该是delete []pa; //shared_ptr<A[]> pa(new A[3]); //shared_ptr<A> pa(new A[3], Mydelete); shared_ptr<A> pa(new A[3], default_delete<A[]>());
1.2.6 lambda 表达式
shared_ptr<A> pa(new A[3], [](A*a) { delete[]a; //lambda表达式 });
1.2.7 移动语义
shared_ptr<A> pa(new A(5)); const shared_ptr<A> &rpa = move(pa); //shared_ptr<A> &&rpa = move(pa); cout << "***************"<<endl; //pa = nullptr; cout << pa.use_count() << endl; cout << rpa.use_count() << endl;
#include <iostream> #include <memory> #include <string> using namespace std; class A { public: A() { cout << "A的无参构造" << endl; } A(int n) { m_a = n; cout << "A的有参构造" << endl; } ~A() { cout << "A的析构函数" << endl; } public: int m_a; }; shared_ptr<A> test() { shared_ptr<A> temp(new A); return temp; } void Func(shared_ptr<A> temp) { cout << temp->m_a << endl; } void Test(int *p) { } void Mydelete(A *pa) { delete[]pa; } int main(void) { #if 0 //int *p = new int(5); //p是裸指针 //shared_ptr<int> p = new int(5); //初始化:调用类型转换构造函数 explicit shared_ptr<int> p(new int(5)); cout << *p << endl; shared_ptr<string> s(new string("helloworld")); cout << *s << endl; int num = 100; //shared_ptr<int> p2(&num); //智能指针常用于堆空间,指向栈空间的时候,会导致内存释放两次 //A *pa = new A(100); //delete pa; shared_ptr<A> pa(new A); shared_ptr<A> res = test(); Func(pa); shared_ptr<A> pa2(pa); //功能:在堆区可以动态分配对象,并返回一个share_ptr(推荐,安全,高效)(构造方法初始化) auto p = std::make_shared<string>("helloworld"); shared_ptr<int> p1 = make_shared<int>(5); cout << *p1 << endl; shared_ptr<string> ps = make_shared<string>("hello world"); cout << *ps << endl; //手动初始化和使用make_shared函数模板初始化有什么区别? //开销小,效率高(数据和引用计数存在同一个空间) //构造函数初始化:数据和引用计数不再同一段空间,需要间接访问 //常规操作: shared_ptr<A> a1 = make_shared<A>(); shared_ptr<A> a2(a1); cout << a2.use_count() << endl; //返回当前有多少个指针指向当前对象或者空间 if (a1.unique()) //判断当前指针是否独享(只有它自己指向该对象)或者空间 { cout << "a1 is unique ptr" << endl; } a1.reset(); if (a1 == nullptr) //NULL:void*() 0 { cout << "a1 is nullptr" << endl; } cout << a2.use_count() << endl; //判断当前指针是否独享该对象,如果独享,则释放该对象,并使该指针指向形参所对应的空间 a1.reset(new A(10)); //shared_ptr<A> pa(new A(188)); //a1.reset(pa); cout << a1->m_a << endl; shared_ptr<int> pd = make_shared<int>(5); Test(pd.get()); #endif //指定删除器:当删除器不起作用的时候,需要自己指定删除器 void(*)(T*) //shared_ptr<A> pa(new A[3]); //delete pa --->应该是delete []pa; //shared_ptr<A[]> pa(new A[3]); //shared_ptr<A> pa(new A[3], Mydelete); //shared_ptr<A> pa(new A[3], default_delete<A[]>()); /*shared_ptr<A> pa(new A[3], [](A*a) { delete[]a; //lambda表达式 });*/ shared_ptr<A> pa(new A(5)); const shared_ptr<A> &rpa = move(pa); //shared_ptr<A> &&rpa = move(pa); cout << "***************"<<endl; //pa = nullptr; cout << pa.use_count() << endl; cout << rpa.use_count() << endl; return 0; }
1.3 auto_ptr
#include <iostream> #include <memory> using namespace std; class Test { public: Test() { cout << "Test的构造函数" << endl; } void print() { cout << "hello world" << endl; } ~Test() { cout <<"Test的析构函数"<<endl; } }; void func1() { Test *pt = new Test; } void func2() { auto_ptr<Test> pt(new Test); pt->print(); //pt.operator->(print()); } int main(void) { func2(); func2(); }
1.4 weak_ptr
1.4.1 概念
弱指针:不会控制对象的生命周期(不会改变对象的引用计数)。 share_ptr释放指向对象时,是不会考虑weak_ptr是否指向该对象。 weak_ptr不是独立指针,不能单独操作所指向的资源。
1.4.2 作用
weak_ptr指针一般用来辅助share_ptr的使用(监视share_ptr指向对象的生命周期) weak_ptr和share_ptr可以相互转化,share_ptr可以直接赋值给weak_ptr 但是反过来是行不通的,需要使用lock函数。
1.4.3 常规操作
(1)lock函数
调用Lock函数用来获取share_ptr(如果对象已经被释放,则返回一个空的share_ptr)
shared_ptr<A> pa(new A(5)); pa.reset(); weak_ptr<A> wpa = pa; auto pb = wpa.lock(); //将弱指针转为共享指针 if(nullptr == pb) { cout << "pb is nullptr" << endl; } else { cout << "pb is not nullptr" << endl; }
(2)use_count
功能:返回有多少个weak_ptr智能指针指向对象(引用计数的个数) 用途:主要用于调试。
(3)expired
功能:判断弱指针是否过期(所检测的对象是否被释放 true /false)
//wpa.reset(); //弱引用计数-1, cout << wpa.use_count() << endl; //返回的是weak_ptr的引用计数 cout << pb.use_count() << endl; if (wpa.expired()) //判断当前弱指针指向的对象是否被释放,弱被释放,返回true,否则返回false { cout << "wpa poniter class is free" << endl; }
(4) 循环引用
#include <iostream> #include <memory> #include <string> using namespace std; class Child; class Parent; class A { public: A() { cout << "A的无参构造" << endl; } A(int n) { m_a = n; cout << "A的有参构造" << endl; } ~A() { cout << "A的析构函数" << endl; } public: int m_a; }; class Parent { public: Parent() { cout << "Parent的构造函数" << endl; } ~Parent() { cout << "parent的析构函数" << endl; } weak_ptr<Child> c; }; class Child :public Parent { public: Child() { cout << "Child的构造函数" << endl; } ~Child() { cout << "Child的析构函数" << endl; } weak_ptr<Parent> p; }; int main(void) { #if 0 //weak_ptr<A> wpa(new A(5)); //不能独立操作一块空间 shared_ptr<A> pa(new A(5)); //weak_ptr:类模板,弱指针(弱引用计数) weak_ptr<A> wpa = pa; weak_ptr<A> wpb = pa; weak_ptr<A> wpc = pa; //弱引用不会影响其生命周期,无论多少个弱引用指向这段空间,只要强引用计数为0,则释放这段空间 //常规操作: shared_ptr<Parent> pp(new Parent); shared_ptr<Child> cc(new Child); pp->c = cc; cc->p = pp; cout << "hello world" << endl; #endif shared_ptr<A> pa(new A(5)); //pa.reset(); weak_ptr<A> wpa = pa; auto pb = wpa.lock(); //将弱指针转为共享指针 if(nullptr == pb) { cout << "pb is nullptr" << endl; } else { cout << "pb is not nullptr" << endl; } //wpa.reset(); //弱引用计数-1, cout << wpa.use_count() << endl; //返回的是weak_ptr的引用计数 cout << pb.use_count() << endl; if (wpa.expired()) //判断当前弱指针指向的对象是否被释放,弱被释放,返回true,否则返回false { cout << "wpa poniter class is free" << endl; } return 0; }
(5) share_ptr & weak_ptr
尺寸:share_ptr 和 weak_ptr一样大,都是裸指针的两倍
#include <iostream> #include <memory> #include <string> using namespace std; class Child; class Parent; class A:public enable_shared_from_this<A> { public: A() { cout << "A的无参构造" << endl; } A(int n) { m_a = n; cout << "A的有参构造" << endl; } //A *GetAddr() shared_ptr<A> GetAddr() { //return this; //shared_ptr<A> tmp(this); //return tmp; //实现原理: //其内部有一个weak_ptr类型的成员变量_wptr //当shared_ptr构造的时候,如果其模板类型继承了enable_shared_from_this<T>,则堆_wptr进行初始化操作 //这样在调用shared_from_this()的时候,就能通过weak_ptr构造出对应的shared_ptr return shared_from_this(); //和pa共享其所有权 } ~A() { cout << "A的析构函数" << endl; } public: int m_a; }; class Parent { public: Parent() { cout << "Parent的构造函数" << endl; } ~Parent() { cout << "parent的析构函数" << endl; } weak_ptr<Child> c; }; class Child :public Parent { public: Child() { cout << "Child的构造函数" << endl; } ~Child() { cout << "Child的析构函数" << endl; } weak_ptr<Parent> p; }; int main(void) { #if 0 //weak_ptr<A> wpa(new A(5)); //不能独立操作一块空间 shared_ptr<A> pa(new A(5)); //weak_ptr:类模板,弱指针(弱引用计数) weak_ptr<A> wpa = pa; weak_ptr<A> wpb = pa; weak_ptr<A> wpc = pa; //弱引用不会影响其生命周期,无论多少个弱引用指向这段空间,只要强引用计数为0,则释放这段空间 //常规操作: shared_ptr<Parent> pp(new Parent); shared_ptr<Child> cc(new Child); pp->c = cc; cc->p = pp; cout << "hello world" << endl; shared_ptr<A> pa(new A(5)); //pa.reset(); weak_ptr<A> wpa = pa; auto pb = wpa.lock(); //将弱指针转为共享指针 if(nullptr == pb) { cout << "pb is nullptr" << endl; } else { cout << "pb is not nullptr" << endl; } //wpa.reset(); //弱引用计数-1, cout << wpa.use_count() << endl; //返回的是weak_ptr的引用计数 cout << pb.use_count() << endl; if (wpa.expired()) //判断当前弱指针指向的对象是否被释放,弱被释放,返回true,否则返回false { cout << "wpa poniter class is free" << endl; } shared_ptr<int> p(new int(5)); cout << sizeof(p) << endl; cout << sizeof(int *) << endl; weak_ptr<int> wp = p; cout << sizeof(wp) << endl; #endif //局部对象释放两次,A自己释放一次,share_ptr还会释放一次 /*A a; shared_ptr<A> tmp = a.GetAddr();*/ /* shared_ptr<A> GetAddr() { //return this; shared_ptr<A> tmp(this); return tmp; } */ shared_ptr<A> pa(new A()); auto tmp = pa->GetAddr(); cout << pa.use_count() << endl; cout << tmp.use_count() << endl; int * pt = new int(); shared_ptr<int> spt1(pt); shared_ptr<int> spt2(pt); std::cout << "spt1.use_count() = " << spt1.use_count() << std::endl; std::cout << "spt2.use_count() = " << spt2.use_count() << std::endl; return 0; }
1.4.4 总结
优点:防止内存泄漏 缺点:造成不必要的开销