一.unique_ptr
定义:
独享它指向的对象。即,同时只有一个unique_ptr指向同一个对象,当unique_ptr销毁时,指向的对象也被销毁
初始化:
//方法一
unique_ptr<AA> p0(new AA("西施"));//分配内存并初始化
//方法二
unique_ptr<AA> p0=make_unique<AA>("西施");//C++14
//方法三
AA *p=new AA("西施");
unique_ptr p0(p);
使用方法:
- 重载* 、->操作符,可以像指针使用unique_ptr
- 不支持拷贝和赋值
- 不要使用同个裸指针初始化多个unique_ptr
- get()方法返回裸指针
- 不要用unique_ptr管理不是new分配的内存
class AA {
public:
string m_name;
AA() {
cout << m_name << "调用构造函数AA()" << endl;
}
AA(const string& name) :m_name(name) {
cout << "调用构造函数AA(const string& name)" << endl;
}
~AA() {
cout << "调用析构函数" << endl;
}
};
int main() {
unique_ptr<AA> pu1(new AA("西施"));
cout << "裸指针的值为" << pu1 << endl;//输出地址1770
cout << "pu1输出的结果为" << pu1 << endl;//输出地址1770
cout << "pu.get()输出结果" << pu1.get() << endl;//输出地址1770
cout << "pu的地址是:" << &pu1 << endl;//输出地址:F738
//赋值
AA* p = new AA("貂蝉");
unique_ptr pu2 = p;//报错
unique_ptr<AA> pu3 = new AA("西施");//报错
unique_ptr pu4 = pu1;//报错
}
使用技巧:
- 将unique_ptr赋值给另一个,若源unique_ptr是临时右值,编译器允许;若源unique_ptr存在一段时间,则禁止;(右值:就像是我们拿起一个临时使用的物品,用完之后就会丢弃掉)
unique_ptr<AA> func(){
unique_ptr<AA> pp (new AA("西施3"));
return pp;
}
int main(){
unique_ptr<AA> pu1(new AA("西施1"));
unique_ptr<AA> pu2;
pu2=unique_ptr<AA> (new AA("西施2"));
cout<<"调用func()之前"<<endl;
pu2=func();
cout<<"调用func()之后"<<endl;
}
- 用nullptr给unique_ptr赋值将释放对象,空的unique_ptr==nullptr;
int main(){
unique_ptr<AA> pu(new AA('西施');
cout<<"赋值前"<<endl;
if(pu!=nullptr) cout<<"pu不是空的"<<endl;
pu=nullptr;
cout<<"赋值后"<<endl;
if(pu==nullptr) cout<<"pu是空的"<<endl;
}
- release()释放对指针的控制权,将unique_ptr置空,返回裸指针;
- std::move()可以转移对指针的控制权
void func(const AA* a){
cout<<a->m_name<<endl;
}
int main(){
unique_ptr<AA> pu(new AA('西施');
cout<<"开始调用函数"<<endl;
func(pu.get());
//func(pu.release());
//func(pu);
//func(move(pu));
cout<<"调用函数完成"<<endl;
}
- reset()释放对象
- swap()交换两个unique_ptr控制权
- unique_ptr不是绝对安全,若程序中途调用exit()退出,全局unique_ptr自动释放,但是局部unique_ptr无法释放
- unique_ptr支持数组具体化,因为重载了操作符[],操作符[]返回的是引用
二.shared_ptr
定义:
shared_ptr共享他指向的对象,多个shared_ptr指向相同的对象,内部采用计数器机制实现
- 当新的shared_ptr与对象关联,引用计数器+1;
- 当shared_ptr超出作用域,引用计数器-1
- 当引用计数器为0时,释放对象
基本用法:
shared_ptr构造函数也是explicit,但是没有删除拷贝构造和赋值函数
初始化:
//方法一
shared_ptr<AA> p0(new AA("西施");
//方法二
shared_ptr<AA> p0=make_shared<AA>("西施");
//方法三
AA * p=new AA("西施");
shared_ptr<AA> p0(p);
//方法四
shared_ptr<AA> p0(new AA("西施");
shared_ptr<AA> p1(p0);//计数器+1
shared_ptr<AA> p1=p0;//计数器+1
使用方法:
- 重载 *、->
- use_count()方法返回引用计数器的值
- unique(),若use_count()为1,返回true
- get()返回裸指针
- 不要用同个裸指针初始化多个share_ptr;
- 不要用shared_ptr管理不是new分配的内存
使用技巧:
- 用nullptr给shared_ptr赋值,计数器-1;若计数器为0则释放空间。空的shared_ptr==nullptr
- std::move()转移对指针控制权,还可将unique_ptr转移成share_ptr
- reset()改变与资源的关联关系
- unique_ptr效率更高,占用资源更少
三.weak_ptr
定义:
解决shared_ptr循环引用问题
循环引用(若A没死,则B也不死。若B没死,A也不死)
class AA {
public:
string m_name;
AA() {
cout << m_name << "调用构造函数AA()" << endl;
}
AA(const string& name) :m_name(name) {
cout << "调用构造函数AA(const string& name)" << endl;
}
~AA() {
cout << "调用析构函数" << endl;
}
shared_ptr<AA> m_p;
};
class BB{
public:
string m_name;
BB() {
cout << m_name << "调用构造函数AA()" << endl;
}
BB(const string& name) :m_name(name) {
cout << "调用构造函数AA(const string& name)" << endl;
}
~BB() {
cout << "调用析构函数" << endl;
}
shared_ptr<BB> m_p;
};
int main(){
shared_ptr<AA> pa=make_shared<AA>("西施a");
shared_ptr<BB> pb=make_shared<BB>("西施b");
cout<<"pa.use_count()="<<pa.use_count()<<endl;
cout<<"pb.use_count()="<<pb.use_count()<<endl;
pa->m_p=pb;
pb->m_p=pa;
cout<<"pa.use_count()="<<pa.use_count()<<endl;
cout<<"pb.use_count()="<<pb.use_count()<<endl;
}
主要成员函数:
lock();//返回shared_ptr
expired();//判断资源是否过期
线程安全问题:
- 单线程安全,多线程不安全
int main(){
shared_ptr<AA> pa=make_shared<AA>("西施a");
{
shared_ptr<BB> pb=make_shared<BB>("西施b");
pa->m_p=pb;
pb->m_p=pa;
if(pa->m_p.expired()==true)
cout<<"语句块内部:pa->m_p已过期"<<endl;
else
cout<<"语句块内部:pa->m_p.lock()->m_name"<<pa->m_p.lock()->m_name<<endl;
}
if(pa->m_p.expired()==true)
cout<<"语句块外部:pa->m_p已过期"<<endl;
else
cout<<"语句块外部:pa->m_p.lock()->m_name"<<pa->m_p.lock()->m_name<<endl;
}
- 线程安全
int main(){
shared_ptr<AA> pa=make_shared<AA>("西施a");
{
shared_ptr<BB> pb=make_shared<BB>("西施b");
pa->m_p=pb;
pb->m_p=pa;
shared_ptr<BB> pp=pa->m_p.lock();
if(pp==nullptr)
cout<<"语句块内部:pa->m_p已过期"<<endl;
else
cout<<"语句块内部:pp->m_name="<<pp->m_name<<endl;
}
shared_ptr<BB> pp=pa->m_p.lock();
if(pp==nullptr)
cout<<"语句块外部:pa->m_p已过期"<<endl;
else
cout<<"语句块外部:pp->m_name"<<pp->m_name<<endl;
}