指独享指向的对象。
同一时间只有一个unique_ptr指向同一个对象,当unique_ptr被销毁时,该对象也被销毁
包含 memory
头文件
//方法一
unique_ptr<CBB>pp(new CBB("貂蝉",20));//分配内存并初始化
//方法二 C++14标准
unique_ptr<CBB>p0= std::make_unique<CBB>("王昭君",21);
//方法三
CBB *p = new CBB("西施",18);
//假设我们忘记delete指针p了 那么不会调用析构函数
unique_ptr<CBB>pt(p);//我们使用unique_ptr智能指针管理p 用已经存在的地址初始化
cout<<"裸指针地址:"<<pp.get()<<endl;
cout<<"pp的值:"<<pp<<endl;
cout<<"pp的地址:"<<&pp<<endl;
/*
裸指针地址:0x2be260c62d0
pp的值:0x2be260c62d0
pp的地址:0xff023ff808
*/
class CBB{
public:
int cbb;
string m_name;
CBB(){
cout<<"默认构造函数"<<endl;
}
CBB(string name,int num):m_name(name),cbb(num){
cout<<"带参数的构造函数"<<name<<endl;
}
~CBB(){
cout<<"析构函数"<<endl;
}
};
unique_ptr<CBB> fun(){
unique_ptr<CBB>p(new CBB("小乔",100));
return p;
}
unique_ptr<CBB>p0(new CBB("貂蝉",20));
unique_ptr<CBB>p1;
// p1=p0;//报错 这样不可以 因为p0还存在
// 匿名对象赋值 允许 匿名对象仅存活在该语句,是临时的
p1= unique_ptr<CBB>(new CBB("妲己",2100));
cout<<"fun之前"<<endl;
//本身p1管理这name为妲己的CBB对象,但是此时p1管理fun返回的CBB对象,那么赋值完毕之后要释放
p1=fun();//这里能接受的原因时fun返回的是临时对象,如果返回的是全局变量那么肯定报错
cout<<"fun之后"<<endl;
/*
带参数的构造函数貂蝉
带参数的构造函数妲己
fun之前
带参数的构造函数小乔
析构函数
fun之后
析构函数
析构函数
*/
unique_ptr<CBB>p0(new CBB("貂蝉",20));//分配内存并初始化
p0= nullptr;
cout<<"p0=nullptr"<<endl;
/*
带参数的构造函数貂蝉
析构函数
p0=nullptr
*/
//析构函数先于最后一个调试语句输出,说明给智能指针赋值nullptr后就释放了对象
void func1(const CBB*a){
cout<<a->m_name<<endl;
}
void func2(CBB*a){
cout<<a->m_name<<endl;
delete a;
}
void func3(unique_ptr<CBB>&c){
cout<<c->m_name<<endl;
}
void func4(unique_ptr<CBB>c){
cout<<c->m_name<<endl;
}
int main() {
//func1 2 3 4要一个一个调用
unique_ptr<CBB>pu(new CBB("貂蝉",20));//分配内存并初始化
cout<<"开始调用函数"<<endl;
func1(pu.get()); //函数需要一个裸指针,但是不对裸指针负责(不释放)
/*
开始调用函数
貂蝉
调用函数完成
析构函数
*/
func2(pu.release());//函数需要一个裸指针,并且对裸指针负责(释放)
/*
开始调用函数
貂蝉
析构函数
调用函数完成
*/
func3(pu);//函数需要一个unique_ptr指针,但是不对裸指针负责(不释放)
/*
开始调用函数
貂蝉
调用函数完成
析构函数
* */
//move将对裸指针的控制权交给函数形参
func4(std::move(pu));//函数需要一个unique_ptr指针,并且对裸指针负责(释放)
/*
开始调用函数
貂蝉
析构函数
调用函数完成
*/
cout<<"调用函数完成"<<endl;
void reset(T*_ptr=(T*)nullptr);
p.reset();//释放p指向的资源对象
p.reset(nullptr);//释放p指向的资源对象
p.reset(new AA("a"));//释放p指向的资源对象,同时指向新的对象
unique_ptr<int[]>p(new int[3]);//不指定初始值
unique_ptr<int[]>p (new int[3]{1,2,3});//指定初始值
共享它指向的对象
多个shared ptr 可以指向(关联)相同的对象,在内部采用计数机制来实现
当新的shared_ptr与对象关联时,引用计数器+1
当shared_ptr超出作用域时,引用计数器-1
引用计数器=0,没有任何的shared_ptr与对象关联,释放该对象
shared_ptr的构造函数也是explicit,但是没有删除拷贝构造和赋值函数
//方法一
shared_ptr<CBB>pp(new CBB("貂蝉",20));//分配内存并初始化
//方法二 C++11标准
shared_ptr<CBB>p0= std::make_shared<CBB>("王昭君",21);
//方法三
CBB *p = new CBB("西施",18);
shared_ptr<CBB>pt(p);//用已经存在的地址初始化
//方法四
CBB *p = new CBB("西施",18);
shared_ptr<CBB>pt(p);//用已经存在的地址初始化
shared_ptr<CBB>p1 = pt;
shared_ptr<CBB>p2(pt);
use_count
方法返回引用计数器的值unique()
方法,如果 use count()为1,返回 true,否则返回 falseshared_ptr
指针(会造成同一块内存多次释放,操作野指针)get
方法返回裸指针shared_ptr
管理不是new分配的内存在默认情况下,智能指针过期的时候,用 delete 原始指针;释放它管理的资源
程序员可以自定义删除器,改变智能指针释放资源的行为。
删除器可以是全局函数、仿函数和 Lambda 表达式,形参为原始指针(裸指针)
void deletefunc(CBB*b){
cout<<"自定义删除器(全局函数)"<<endl;
delete b;
}
class deleteclass{
public:
void operator()(CBB*p){
cout<<"自定义删除器(仿函数)"<<endl;
delete p;
}
};
int main() {
std::shared_ptr<CBB>p1(new CBB("xx",20),deletefunc);
std::shared_ptr<CBB>p2(new CBB("xxxxx",22),deleteclass());
unique_ptr<CBB, decltype(deletefunc)*>p3(new CBB("ddd",88), deletefunc);
unique_ptr<CBB, deleteclass>p4(new CBB("ddd",88), deleteclass());
}
shared ptr 内部维护了一个共享的引用计数器,多个 shared ptr 可以指向同一个资源
如果出现了循环引用的情况,引用计数永远无法归0,资源不会被释放
weak ptr 是为了配合 shared ptr 而引入的,它指向一个由 shared ptr 管理的资源但不影响资源的生命周期
也就是说,将一个weak ptr 绑定到一个shared ptr 不会改变 shared ptr 的引用计数
不论是否有 weak ptr 指向,如果最后一个指向资源的 shared ptr 被销毁,资源就会被释放
weak ptr 更像是 shared ptr 的助手而不是智能指针
weak_ptr没有重载 -> 和 * 不能直接访问资源
weak_ptr精髓:
weak_ptr和shared_ptr主要用于多线程的问题