目录
一、引入背景
1> C++中在堆区申请空间和释放空间需要使用new和delete完成
2> 多个指针指向同一个内存空间,释放其中一个的空间,另一个还在继续使用(悬空指针)
3> 只是申请了内存空间,使用后忘记释放内存空间,堆区对象没有得到析构
4> 栈取申请的对象空间,在脱离对象空间后,会自动调用析构函数完成资源的回收,但是堆区的不会自动释放
#include <iostream>
using namespace std;
class Test
{
private:
string name;
public:
Test() {cout<<"Test::无参构造"<<endl;}
Test(string n):name(n) {cout<<name<<"::有参构造"<<endl;}
~Test() {cout<<name<<"::析构函数"<<endl;}
};
int main()
{
Test *p = new Test("张飞");
cout << "Hello World!" << endl;
return 0;
}
5> 总结:上述例子中,在堆区申请一个对象空间,但是没有手动释放空间,造成对象没有析构,为了保证堆区空间使用的安全性,我们引入了智能指针,目的是更加安全的使用堆区空间。
二、智能指针
1> C++11标准提供了两种智能指针,分别是unique_ptr(独占智能指针)、shared_ptr(共享智能指针)
2> 除了上述两种指针外,还有auto_ptr(自动智能指针,已弃用)、weak_ptr(弱智能指针,辅助shared_ptr作用)
3> 以上所有智能指针都在头文件:#include中
4> 智能指针是类模板,在栈区创建智能指针对象
5> 把普通指针交给智能指针管理
6> 智能指针对象过期时,析构函数会自动释放智能指针管理的指针空间
三、unique_ptr(独占智能指针)
3.1 独占智能指针的概述
独占智能指针会“拥有”它所指向的对象,某一时刻,只能有一个unique_ptr指向给定的对象,当该指针被销毁时,指向的对象也会随之释放。
3.2 类的原型
template <typename T, typename D = default_delete<T>>
class unique_ptr
{
public:
explicit unique_ptr(pointer p) noexcept; // 不可用于转换函数。
~unique_ptr() noexcept;
T& operator*() const; // 重载*操作符。
T* operator->() const noexcept; // 重载->操作符。
unique_ptr(const unique_ptr &) = delete; // 禁用拷贝构造函数
unique_ptr& operator=(const unique_ptr &) = delete; // 禁用赋值函数
unique_ptr(unique_ptr &&) noexcept; // 右值引用。
unique_ptr& operator=(unique_ptr &&) noexcept; // 右值引用
private:
pointer ptr; // 内置的指针。
};
3.3 初始化
方法一: unique_ptr<AA> p0(new AA("西施"));// 分配内存并初始化。
方法二: unique_ptr<AA> p0 = make_unique<AA>("西施"); // C++14标准。
方法三: AA* p = new AA("西施"); unique_ptr<AA> p0(p); // 用已存在的地址初始化。
1> 方法三
#include <iostream>
#include<memory>
using namespace std;
class Test
{
public:
string name; //名字
Test() {cout<<name<<"::无参构造"<<endl;} //无参构造
Test(string n):name(n) {cout<<name<<"::有参构造"<<endl;} //有参构造
~Test() {cout<<name<<"::析构函数"<<endl;} //析构函数
};
int main()
{
Test *p1 = new Test("张三"); //在堆区申请空间
unique_ptr<Test> up1(p1); //使用原始指针实例化一个指针指针
cout<<"name = "<<(*p1).name<<endl; //指针找到对象使用
cout<<"name = "<<p1->name<<endl; //原始指针直接使用
cout<<"name = "<<(*up1).name<<endl; //智能指针访问
cout<<"name = "<<up1->name<<endl; //智能指针访问
cout << "********程序到此结束!********" << endl;
return 0;
}
2> 使用方式1:
#include <iostream>
#include<memory>
using namespace std;
class Test
{
public:
string name; //名字
Test() {cout<<name<<"::无参构造"<<endl;} //无参构造
Test(string n):name(n) {cout<<name<<"::有参构造"<<endl;} //有参构造
~Test() {cout<<name<<"::析构函数"<<endl;} //析构函数
};
int main()
{
unique_ptr<Test> up1(new Test("张三")); //使用原始指针实例化一个指针指针
cout<<"name = "<<(*up1).name<<endl; //智能指针访问
cout<<"name = "<<up1->name<<endl; //智能指针访问
cout << "********程序到此结束!********" << endl;
return 0;
}
3> 使用方法2只有C++14标准后才能使用,C++11标准不支持
3.4 独占智能指针的注意事项
1> 重载的*和->运算符重载,所以可以跟像使用普通指针一样使用该智能指针
2> 不支持拷贝构造和拷贝赋值函数
3> 不要使用一个原始指针初始化多个unique_ptr
4> get()函数可以返回该智能指针的原始指针
5> 不要使用unique_ptr指向非new申请的空间
6> 有智能指针指向原始指针后,就不要再用原始指针手动释放了
#include <iostream>
#include<memory>
using namespace std;
class Test
{
public:
string name; //名字
Test() {cout<<name<<"::无参构造"<<endl;} //无参构造
Test(string n):name(n) {cout<<name<<"::有参构造"<<endl;} //有参构造
~Test() {cout<<name<<"::析构函数"<<endl;} //析构函数
};
int main()
{
Test *p1 = new Test("张三");
unique_ptr<Test> up1(p1); //使用原始指针实例化一个指针指针
unique_ptr<Test> up2(p1); //使用一个原始指针实例化多个智能指针
cout<<"name = "<<(*up1).name<<endl; //智能指针访问
cout<<"name = "<<up1->name<<endl; //智能指针访问
cout << "********程序到此结束!********" << endl;
return 0;
}
7> 智能指针作为函数参数传递时,传递引用,不要传递值,因为智能指针没有拷贝构造函数
#include <iostream>
#include<memory>
using namespace std;
class Test
{
public:
string name; //名字
Test() {cout<<name<<"::无参构造"<<endl;} //无参构造
Test(string n):name(n) {cout<<name<<"::有参构造"<<endl;} //有参构造
~Test() {cout<<name<<"::析构函数"<<endl;} //析构函数
};
//void fun(unique_ptr<Test> up) //定义时不会报错,但是使用时会报错
void fun(unique_ptr<Test> &up)
{
}
int main()
{
Test *p1 = new Test("张三");
unique_ptr<Test> up1(p1); //使用原始指针实例化一个指针指针
cout<<"name = "<<(*up1).name<<endl; //智能指针访问
cout<<"name = "<<up1->name<<endl; //智能指针访问
//调用函数传递智能指针的值
fun(up1); //报错,会告诉没有拷贝构造函数
cout << "********程序到此结束!********" << endl;
return 0;
}
8> 智能指针不支持:+、-、++、--
3.5 智能指针的更多技巧
1> 将一个智能指针unique_ptr赋值给另一个指针时,可以赋值右值(移动构造存在),但是不能赋值左值(拷贝构造不存在)
2> 使用nullptr给unique_ptr赋值时,会自动释放对象
#include <iostream>
#include<memory>
using namespace std;
class Test
{
public:
string name; //名字
Test() {cout<<name<<"::无参构造"<<endl;} //无参构造
Test(string n):name(n) {cout<<name<<"::有参构造"<<endl;} //有参构造
~Test() {cout<<name<<"::析构函数"<<endl;} //析构函数
};
int main()
{
Test *p1 = new Test("张三");
unique_ptr<Test> up1(p1); //使用原始指针实例化一个指针指针
cout<<"name = "<<(*up1).name<<endl; //智能指针访问
cout<<"name = "<<up1->name<<endl; //智能指针访问
up1 = nullptr; //用空指针给智能指针赋值时,会释放智能指针指向的对象
cout << "********程序到此结束!********" << endl;
return 0;
}
3> 使用release()函数,可以释放unique_ptr的指针,并且将原指针返回
4> std::move函数,可以转移原始指针的控制权,本质上调用的时移动构造函数
#include <iostream>
#include<memory>
using namespace std;
class Test
{
public:
string name; //名字
Test() {cout<<name<<"::无参构造"<<endl;} //无参构造
Test(string n):name(n) {cout<<name<<"::有参构造"<<endl;} //有参构造
~Test() {cout<<name<<"::析构函数"<<endl;} //析构函数
};
//函数1需要一个指针,但是不对这个指针负责
void fun1(const Test *p)
{
cout<<"fun1::"<<p->name<<endl;
}
//函数2需要一个指针,并且对这个指针负责
void fun2(Test *p)
{
cout<<"fun2::"<<p->name<<endl;
delete p;
}
//函数3需要一个智能指针,但是不对这个指针负责
void fun3(unique_ptr<Test> &up)
{
cout<<"fun3::"<<up->name<<endl;
}
//函数4需要一个智能指针,并对这个指针负责
void fun4(unique_ptr<Test> up)
{
cout<<"fun3::"<<up->name<<endl;
}
int main()
{
unique_ptr<Test> up1(new Test("张飞")); //在堆区空间实例化一个对象,托管到智能指针
cout<<"函数调用开始"<<endl;
// fun1(up1.get()); //调用功能1函数,不会对指针负责
// fun2(up1.release()); //调用功能2函数,会对指针负责
// fun3(up1); //需要使用智能指针的引用,函数内不会对指针负责
fun4(move(up1)); //使用一个智能指针,函数内对指针负责
cout << "********程序到此结束!********" << endl;
return 0;
}
5> reset()函数释放对象
函数原型:void reset(pointer __p = pointer())
使用方法: up->reset(); //释放up对象指向的资源
up->reset(nullptr); //释放up对象指向的资源
up->reset(new Test("夏侯")); //释放up对原对象的资源,并指向新对象
#include <iostream>
#include<memory>
using namespace std;
class Test
{
public:
string name; //名字
Test() {cout<<name<<"::无参构造"<<endl;} //无参构造
Test(string n):name(n) {cout<<name<<"::有参构造"<<endl;} //有参构造
~Test() {cout<<name<<"::析构函数"<<endl;} //析构函数
};
int main()
{
unique_ptr<Test> up1(new Test("张飞")); //在堆区空间实例化一个对象,托管到智能指针
cout<<"函数调用开始"<<endl;
//up1.reset();
up1.reset(new Test("夏侯")); //释放原来对象的空间,指向新的空间
cout << "********程序到此结束!********" << endl;
return 0;
}
6> swap()函数交换两个unique_ptr的使用权
#include <iostream>
#include<memory>
using namespace std;
class Test
{
public:
string name; //名字
Test() {cout<<name<<"::无参构造"<<endl;} //无参构造
Test(string n):name(n) {cout<<name<<"::有参构造"<<endl;} //有参构造
~Test() {cout<<name<<"::析构函数"<<endl;} //析构函数
};
int main()
{
unique_ptr<Test> up1(new Test("张飞")); //在堆区空间实例化一个对象,托管到智能指针
unique_ptr<Test> up2(new Test("夏侯"));
cout<<"函数调用开始"<<endl;
up1.swap(up2); //调用两个指针的使用权
cout<<"up1->name = "<<up1->name<<endl; //夏侯
cout<<"up2->name = "<<up2->name<<endl; //张飞
cout << "********程序到此结束!********" << endl;
return 0;
}
7> unique_ptr也可以有原始指针的特性,当指向一个继承体系内的基类对象时,也有多态的特性,如同原始指针管理基类对象和派生类对象一样
#include <iostream>
#include<memory>
using namespace std;
class Test
{
public:
string name; //名字
Test() {cout<<name<<"::无参构造"<<endl;} //无参构造
Test(string n):name(n) {cout<<name<<"::有参构造"<<endl;} //有参构造
~Test() {cout<<name<<"::析构函数"<<endl;} //析构函数
virtual void show()
{
cout<<"我是父类"<<endl;
}
};
class Demo:public Test
{
public:
void show() override
{
cout<<"我是子类"<<endl;
}
};
int main()
{
unique_ptr<Test> up1(new Demo); //父类指针指向子类对象
cout<<"函数调用开始"<<endl;
up1->show(); //调用子类中重写的父类的虚函数
cout << "********程序到此结束!********" << endl;
return 0;
}
8> 智能指针也不是绝对安全的,当程序内有exit()退出程序时,全局智能指针会释放空间,但是局部智能指针不会
#include <iostream>
#include<memory>
using namespace std;
class Test
{
public:
string name; //名字
Test() {cout<<name<<"::无参构造"<<endl;} //无参构造
Test(string n):name(n) {cout<<name<<"::有参构造"<<endl;} //有参构造
~Test() {cout<<name<<"::析构函数"<<endl;} //析构函数
virtual void show()
{
cout<<"我是父类"<<endl;
}
};
int main()
{
unique_ptr<Test> up1(new Test("张飞")); //父类指针指向子类对象
cout<<"函数调用开始"<<endl;
exit(0); //手动退出程序
cout << "********程序到此结束!********" << endl;
return 0;
}
#include <iostream>
#include<memory>
using namespace std;
class Test
{
public:
string name; //名字
Test() {cout<<name<<"::无参构造"<<endl;} //无参构造
Test(string n):name(n) {cout<<name<<"::有参构造"<<endl;} //有参构造
~Test() {cout<<name<<"::析构函数"<<endl;} //析构函数
virtual void show()
{
cout<<"我是父类"<<endl;
}
};
//全局定义智能指针
unique_ptr<Test> up1(new Test("张飞")); //父类指针指向子类对象
int main()
{
cout<<"函数调用开始"<<endl;
exit(0); //手动退出程序
cout << "********程序到此结束!********" << endl;
return 0;
}
9> unique_ptr提供了支持数组的具体化版本数组版本的unique_ptr,重载了[]运算符,返回的是引用,可以作为左值使用
#include <iostream>
#include<memory>
using namespace std;
class Test
{
public:
string name; //名字
Test() {cout<<name<<"::无参构造"<<endl;} //无参构造
Test(string n):name(n) {cout<<name<<"::有参构造"<<endl;} //有参构造
~Test() {cout<<name<<"::析构函数"<<endl;} //析构函数
};
int main()
{
//1、普通指针指向数组的使用
// Test *p = new Test[2];
Test *p = new Test[2]{string("张飞"), string("夏侯")};
// p[0].name = "张飞";
// p[1].name = "夏侯";
// cout<<"p[0].name = "<<p[0].name<<" p[1].name = "<<p[1].name<<endl;
// delete [] p;
//2、使用智能指针指向数组
unique_ptr<Test[]> up(new Test[2]); //类型后需要加一个空的中括号
//unique_ptr<Test[]> up(new Test[2]{string("张飞"), string("夏侯")});
up[0].name = "张飞";
up[1].name = "夏侯";
cout<<"up[0].name = "<<up[0].name<<" up[1].name = "<<up[1].name<<endl;
cout << "********程序到此结束!********" << endl;
return 0;
}
四、shared_ptr(共享智能指针)
4.1 概述
shared_ptr共享他指向的对象,多个共享指针可以指向(关联)相同的对象,在内部采用计数器机制来实现当新的shared_ptr与对象关联时,引用计数器增加1当shared_ptr超出作用域时,引用计数器减1,当引用计数器变为0时,则表示没有任何shared_ptr与对象关联,则释放该对象
#include <iostream>
#include<memory>
using namespace std;
class Test
{
public:
string name; //名字
Test() {cout<<name<<"::无参构造"<<endl;} //无参构造
Test(string n):name(n) {cout<<name<<"::有参构造"<<endl;} //有参构造
~Test() {cout<<name<<"::析构函数"<<endl;} //析构函数
};
int main()
{
Test *p = new Test("张飞"); //使用原始指针指向一个对象
shared_ptr<Test> sp1(p); //构造一个共享智能指针
cout<<"sp1.use_count = "<<sp1.use_count()<<endl; //显式当前指针的引用计数器 1
cout << "********程序到此结束!********" << endl;
return 0;
}
4.2 基本使用
shared_ptr的构造函数也是explicit,但是没有删除拷贝构造函数和拷贝赋值函数
1> 初始化
方法一:shared_ptr<AA> p0(new AA("西施"));// 分配内存并初始化。方法二:shared_ptr<AA> p0 = make_unique<AA>("西施"); // C++11标准,推荐使用,效率更高方法三:AA* p = new AA("西施");shared_ptr<AA> p0(p); // 用已存在的地址初始化。方法四:shared_ptr<AA> p0(new AA("西施"));// 分配内存并初始化。shared_ptr<AA> p1(p0); //拷贝构造shared_ptr<AA> p2 = p0; //拷贝构造
#include <iostream>
#include<memory>
using namespace std;
class Test
{
public:
string name; //名字
Test() {cout<<name<<"::无参构造"<<endl;} //无参构造
Test(string n):name(n) {cout<<name<<"::有参构造"<<endl;} //有参构造
~Test() {cout<<name<<"::析构函数"<<endl;} //析构函数
};
int main()
{
Test *p = new Test("张飞"); //使用原始指针指向一个对象
shared_ptr<Test> sp1(p); //构造一个共享智能指针
cout<<"sp1.use_count = "<<sp1.use_count()<<endl; //显式当前指针的引用计数器 1
shared_ptr<Test> sp2(sp1); //拷贝构造
shared_ptr<Test> sp3 = sp2; //拷贝构造
cout<<"sp1.use_count = "<<sp1.use_count()<<endl; //显式当前指针的引用计数器 3
cout<<"sp2.use_count = "<<sp2.use_count()<<endl; //显式当前指针的引用计数器 3
cout<<"sp3.use_count = "<<sp3.use_count()<<endl; //显式当前指针的引用计数器 3
cout << "********程序到此结束!********" << endl;
return 0;
}
2> 使用方法
1、智能指针重载了*和->操作符,可以像使用原始指针一样使用shared_ptr
2、use_count()函数返回引用计数器的个数
3、unique()函数,如果use_count()为1,返回true,否则返回false
4、支持普通的拷贝和赋值,左值的shared_ptr的计数器减1,右值的shared_ptr的计数器将加1
left = right;
5、get()函数返回原始指针
6、不要用同一个原始指针区初始化多个shared_ptr
7、不要使用shared_ptr管理不是new分配的空间内存
#include <iostream>
#include<memory>
using namespace std;
class Test
{
public:
string name; //名字
Test() {cout<<name<<"::无参构造"<<endl;} //无参构造
Test(string n):name(n) {cout<<name<<"::有参构造"<<endl;} //有参构造
~Test() {cout<<name<<"::析构函数"<<endl;} //析构函数
};
int main()
{
shared_ptr<Test> spa1(new Test("张飞")); //构造一个共享智能指针
shared_ptr<Test> spa2(spa1); //拷贝构造
shared_ptr<Test> spa3 = spa2; //拷贝构造
cout<<"spa1.use_count = "<<spa1.use_count()<<endl; //张飞的指针个数 3
shared_ptr<Test> spb1(new Test("夏侯")); //构造夏侯的指针
shared_ptr<Test> spb2(spb1);
cout<<"spb1.use_count = "<<spb1.use_count()<<endl; //夏侯的引用计数器 2
spa2 = spb2; //夏侯的引用计数器将加1,张飞的引用计数器减1
cout<<"spa1.use_count = "<<spa1.use_count()<<endl; //张飞的指针个数 2
cout<<"spb1.use_count = "<<spb1.use_count()<<endl; //夏侯的引用计数器 3
cout << "********程序到此结束!********" << endl;
return 0;
}
3> 用于函数参数
跟unique_ptr一样
4> 不支持指针的运算:+、-、++、--
4.3 更多细节
1> 使用nullptr给shared_ptr赋值时,将计数器减1,如果计数器为0,释放对象资源,空的shared_ptr = nullptr;
2> str::move() 可以转移对原始指针的控制权,还可以将unique_ptr转变成shared_ptr
3> reset()改变与资源的关联关系
pp.reset(); //解除与资源的关系,资源的引用计数器减1
pp.reset(new AA("bbb")); //解除与资源的关系,引用计数器减1,关联新资源
4> swap()函数交换两个shared_ptr的控制权
5> shared_ptr也可以像普通指针那样,完成多态的性质,使用方式跟原始指针一致
6> shared_ptr不是绝对安全的,如果程序中调用了exit()退出,全局的shared_ptr会自动释放,局部的shared_ptr无法释放
7> shared_ptr提供的智能指针数组的具体化版本,重载了[],返回值是一个引用,可以作为左值使用
8> shared_ptr的线程安全性:
shared_ptr的引用计数器是线程安全的(引用计数器是原子操作)
多个线程同时读一个shared_ptr对象是线程安全的
如果多个线程对同一个shared_ptr对象进行读和写,则需要加锁
多线程读写shared_ptr所指向的同一个对象,不管是相同的shared_ptr对象,还是不同的shared_ptr对象,都要加锁进行保护
9> 实际开发过程中,unique_ptr能解决的问题,尽量不要使用shared_ptr,因为unique_ptr效率更高,所用资源更少
五、智能指针的删除器(了解)
在默认情况下,智能指针过期的时候,用 delete 原始指针;
释放管理的资源程序员也可以自定义删除器,改变智能指针释放资源的行为
删除器可以是全局函数、仿函数以及Lambda表达式,形参为原始指针
#include <iostream>
#include<memory>
using namespace std;
class Test
{
public:
string name; //名字
Test() {cout<<name<<"::无参构造"<<endl;} //无参构造
Test(string n):name(n) {cout<<name<<"::有参构造"<<endl;} //有参构造
~Test() {cout<<name<<"::析构函数"<<endl;} //析构函数
};
//全局函数作为删除器
void deletefunc(Test *p)
{
cout<<"自定义删除器:全局函数实现"<<endl;
delete p;
}
//定义仿函数作为删除器
class deleteclass
{
public:
void operator()(Test *p)
{
cout<<"仿函数实现删除器"<<endl;
delete p;
}
};
//定义lambda作为删除器
auto deleteLamb = [](Test *p){
cout<<"lambda表达式作为删除器"<<endl;
delete p;
};
int main()
{
//shared_ptr<Test> spa1(new Test("张飞")); //使用默认的删除器
/*shared_ptr<Test> spa1(new Test("张飞"),deletefunc);*/ //使用全局函数作为删除器
// shared_ptr<Test> spa1(new Test("张飞"),deleteclass()); //使用仿函数作为删除器
// shared_ptr<Test> spa1(new Test("张飞"),deleteLamb);
//独占智能指针的删除器的使用
// unique_ptr<Test, decltype (deletefunc)*> up1(new Test("夏侯"), deletefunc); //全局函数作为删除器
unique_ptr<Test, void (*)(Test *)> up1(new Test("夏侯"), deletefunc); //使用函数指针推导
// unique_ptr<Test, deleteclass> up1(new Test("夏侯"), deleteclass()); //仿函数作为删除器
// unique_ptr<Test, decltype (deleteLamb)> up1(new Test("夏侯"), deleteLamb); //lambda表达式作为删除器
cout << "********程序到此结束!********" << endl;
return 0;
}
六、weak_ptr(弱智能指针)
6.1 引入目的
shared_ptr内部维护了一个共享的引用计数器,多个shared_ptr可以指向同一个资源如果出现了循环引用的情况,引用计数器将永远无法归0,资源不会被释放
#include <iostream>
#include<memory>
using namespace std;
class Demo;
class Test
{
public:
string name; //名字
shared_ptr<Demo> sp; //共享智能指针
Test() {cout<<name<<"::无参构造"<<endl;} //无参构造
Test(string n):name(n) {cout<<name<<"::有参构造"<<endl;} //有参构造
~Test() {cout<<name<<"::析构函数"<<endl;} //析构函数
};
class Demo
{
public:
string name; //名字
shared_ptr<Test> sp; //共享智能指针
Demo() {cout<<name<<"::无参构造"<<endl;} //无参构造
Demo(string n):name(n) {cout<<name<<"::有参构造"<<endl;} //有参构造
~Demo() {cout<<name<<"::析构函数"<<endl;} //析构函数
};
int main()
{
shared_ptr<Test> sp1(new Test("张飞"));
shared_ptr<Demo> sp2(new Demo("夏侯"));
//将他们的彼此的共享指针成员指向彼此
sp1->sp = sp2;
sp2->sp = sp1;
cout << "********程序到此结束!********" << endl;
return 0;
}
6.2 weak_ptr是什么
1> weak_ ptr 是为了配合shared_ ptr 而引入的,它指向一个由shared_ ptr 管理的资源但不影响资源的生命周期。也就是说,将-个weak_ ptr 绑定到一个shared_ ptr 不会改变shared_ ptr 的引用计数。
2> 不论是否有weak_ ptr 指向,如果最后一个指向资源的shared_ ptr 被销毁,资源就会被释放。
3> weak_ ptr更像是shared_ ptr 的助手而不是智能指针。
6.3 如何使用weak_ptr
1> weak_ptr没有重载->和*运算符,不能直接访问资源
2> operator=(); 把shared_ptr或weak_ptr赋值给weak_ptr
3> expired(); 判断它指向的资源释放已经过期
4> lock(); 返回shared_ptr,如果资源已经过期,返回空的shared_ptr
5> reset(); 将当前的weak_ptr置空
6> swap(); 交换
7> weak_ptr不控制对象的生命周期,但是,它知道对象是否还活着
用lock()函数可用把它提升为shared_ptr,如果对象还活着,返回有效的shared_ptr,如果对象已经死了,提升会失败,返回一个空的shared_ptr 提升的行为(lock)是线程安全的
6.4 weak_ptr的使用
1> 单线程可用,多线程不安全版本
#include <iostream>
#include<memory>
using namespace std;
class Demo;
class Test
{
public:
string name; //名字
weak_ptr<Demo> sp; //弱智能指针
Test() {cout<<name<<"::无参构造"<<endl;} //无参构造
Test(string n):name(n) {cout<<name<<"::有参构造"<<endl;} //有参构造
~Test() {cout<<name<<"::析构函数"<<endl;} //析构函数
};
class Demo
{
public:
string name; //名字
weak_ptr<Test> sp; //弱智能指针
Demo() {cout<<name<<"::无参构造"<<endl;} //无参构造
Demo(string n):name(n) {cout<<name<<"::有参构造"<<endl;} //有参构造
~Demo() {cout<<name<<"::析构函数"<<endl;
} //析构函数
};
int main()
{
shared_ptr<Test> sp1 = make_shared<Test>("张飞"); //创建一个共享智能指针
{
shared_ptr<Demo> sp2 = make_shared<Demo>("夏侯"); //在局部空间创建一个新对象
//两个类对象的弱指针成员指向对方
sp1->sp = sp2;
sp2->sp = sp1;
if(sp1->sp.expired() == true)
{
cout<<"语句块内部:sp1->sp已经过期"<<endl;
}else
{
cout<<"语句块内部:sp1->sp.lock()->name = "<<sp1->sp.lock()->name<<endl;
}
}
if(sp1->sp.expired() == true)
{
cout<<"语句块外部:sp1->sp已经过期"<<endl;
}else
{
cout<<"语句块外部:sp1->sp.lock()->name = "<<sp1->sp.lock()->name<<endl;
}
cout << "********程序到此结束!********" << endl;
return 0;
}
2> 多线程安全版本
#include <iostream>
#include<memory>
using namespace std;
class Demo;
class Test
{
public:
string name; //名字
weak_ptr<Demo> sp; //弱智能指针
Test() {cout<<name<<"::无参构造"<<endl;} //无参构造
Test(string n):name(n) {cout<<name<<"::有参构造"<<endl;} //有参构造
~Test() {cout<<name<<"::析构函数"<<endl;} //析构函数
};
class Demo
{
public:
string name; //名字
weak_ptr<Test> sp; //弱智能指针
Demo() {cout<<name<<"::无参构造"<<endl;} //无参构造
Demo(string n):name(n) {cout<<name<<"::有参构造"<<endl;} //有参构造
~Demo() {cout<<name<<"::析构函数"<<endl;
} //析构函数
};
int main()
{
shared_ptr<Test> sp1 = make_shared<Test>("张飞"); //创建一个共享智能指针
{
shared_ptr<Demo> sp2 = make_shared<Demo>("夏侯"); //在局部空间创建一个新对象
//两个类对象的弱指针成员指向对方
sp1->sp = sp2;
sp2->sp = sp1;
//定义一个共享智能指针,接收提升后的weak_ptr
shared_ptr<Demo> t = sp1->sp.lock(); //原子操作,线程安全
if(t == nullptr)
{
cout<<"语句块内部:sp1->sp已经过期"<<endl;
}else
{
cout<<"语句块内部:t->name = "<<t->name<<endl;
}
}
//定义一个共享智能指针,接收提升后的weak_ptr
shared_ptr<Demo> t = sp1->sp.lock(); //原子操作,线程安全
if(t == nullptr)
{
cout<<"语句块外部:sp1->sp已经过期"<<endl;
}else
{
cout<<"语句块外部:t->name = "<<t->name<<endl;
}
cout << "********程序到此结束!********" << endl;
return 0;
}