一,什么是智能指针
1.智能指针智能指针就是个类,对普通指针进行封装,不管函数三正常结束还是异常结束,他在析构函数中对指针可以进行智能释放
2.普通指针普通指针在使用完成后需要进行手动释放,且容易造成堆的内存泄漏(忘记释放),二次释放,使用智能指针可以避免这些问题
3 在c++11中智能指针分为3种
包含在头文件中,分别为:shared_ptr、unique_ptr、weak_ptr
4,三种智能指针归纳:
类型 | 功能 | 缺点 |
---|---|---|
shared_ptr | 使用引用次数,当引用次数为0时自动释放 赋 值引用-1 拷贝引用+1 离开作用域自动释放 | 不能循环引用,避免一个原指针被两个shared指针引用 |
unique_ptr | 只能指向一个指针对象,离开作用域后自动释放 | 不能拷贝,赋值 |
weak_ptr | 作为shared_ptr的辅助智能指针,引用shared_ptr 原指针引用数不变,使用lock获取原指针的资源 | 作为shared_ptr的管理者 |
二,三种智能指针
2.1,shared_ptr 智能指针
- shared_ptr
多个指针指向相同的对象
,使用引用计数
,每一个shared_ptr拷贝都指向相同的内存,每使用他一次,内部的引用>计数器+1,每析构一次-1,减为0时,自动删除所指向的堆内存 - 拷贝使得原对象的引用计数增加1,赋值使得原对象引用计数-1,被赋值对象引用+1,当计数为0时,自动释放内存。
*shared_ptr需要避免循环引用
理解下面一端代码,就可理解shared_ptr:
#include <iostream>
#include <memory>
using namespace std;
int main() {
weak_ptr<int> wp;
{
int a=10;
shared_ptr<int> ptra=make_shared<int>(a);
wp=ptra;
cout<<"未进行任何操作的ptra引用个数"<<ptra.use_count()<<endl;
//拷贝 因为被拷贝 有两个指针变量在使用 所以+1
shared_ptr<int> ptra2(ptra);
cout<<"拷贝后ptra引用个数"<<ptra.use_count()<<endl;
int b=20;
int *pb=&a;
shared_ptr<int> ptrb=make_shared<int>(b);
cout<<"初始ptrb的引用个数:"<<ptrb.use_count()<<endl;
//赋值 赋值后取消了对原指针的引用 但是被赋值对象引用+1
ptra2=ptrb;
cout<<"ptrb赋值给ptra2后ptra的引用个数:"<<ptra.use_count()<<endl;
cout<<"当前ptrb的引用个数:"<<ptrb.use_count()<<endl;
//获取智能指针的原始指针
pb=ptrb.get();
cout<<"ptrb的原始指针的值:"<<*pb<<endl;
}
//出了作用域 shared_ptr自动清除,引用归0
cout<<"出了作用域后,ptra的引用个数:"<<wp.use_count()<<endl;
}
2.2 unique_ptr智能指针
- unique
即唯一的,即该智能指针在同一时刻只能指向一个指针对象(通过禁止拷贝,赋值进行实现)但是可以通过move转移所有权,通过release释放所有权 - unique_ptr指针本身的生命周期:从unique_ptr指针创建时开始,直到离开作用域。离开作用域时,若其指向对象,则将其所指对象销毁(默认使用delete操作符,用户可指定其他操作)
理解下面一段代码即可理解uniqque_ptr:
#include <iostream>
#include <memory>
using namespace std;
int main()
{
{
int a=10;
//与shared_ptr不同的是可以直接使用原始指针进行拷贝
unique_ptr<int> uptr(new int(10));
// std::unique_ptr<int> uptr2 = uptr; //不能賦值
//std::unique_ptr<int> uptr2(uptr); //不能拷貝i
cout<<"uptr的原始指针的值:"<<*uptr.get()<<endl;
//转移所有权
unique_ptr<int> uptr2=move(uptr);
//cout<<"uptr所有权转换后的值:"<<*uptr.get()<<endl; //转移后不能获取指针的值
cout<<"uptr2获取所有权后的值:"<<*uptr2.get()<<endl;
uptr2.release(); //释放所有权
//cout<<"uptr2获取所有权后的值:"<<*uptr2.get()<<endl; //释放所有权后不能再获取指针的值
}
//超过uptr的作用域,内存释放
}
2.3 weak_ptr智能指针
weak_ptr是为了配合shared_ptr而引入的一种智能指针,因为它不具有普通指针的行为,没有重载operator*和->,它的最大作用在于协助shared_ptr工作,像旁观者那样观测资源的使用情况。weak_ptr可以从一个shared_ptr或者另一个weak_ptr对象构造,它的构造不会引起指针引用计数的增加,获得资源的观测权
用lock获取原shared_ptr的对象进行操作资源
通过下面代码理解:
#include <iostream>
#include <memory>
int main() {
{
std::shared_ptr<int> sh_ptr = std::make_shared<int>(10);
std::cout <<"当前sh_ptr的引用个数" <<sh_ptr.use_count() << std::endl;
//weak_ptr引用shared-Ptr
std::weak_ptr<int> wp(sh_ptr);
//引用个数不改变
std::cout <<"weak_ptr引用shared_Ptr后的引用个数:"<<wp.use_count() << std::endl;
//wp.expired 等价于use_count==0 即判断被观测的资源是否结束
if(!wp.expired()){
//用过lock获取shared_ptr的对象进行操作资源
std::shared_ptr<int> sh_ptr2 = wp.lock(); //get another shared_ptr
*sh_ptr2 = 100;
std::cout << "通过wp.lock获取shared对象后的引用个数"<<wp.use_count()<<"操作后的值:"<<*sh_ptr.get() << std::endl;
}
}
//离开作用域自动释放
//delete memory
}
循环引用:
例子:一个子类,一个父类,子类引用父类shared指针,父类引用子类shaed指针,当退出域时,二者的引用都不能降为0,导致不能正常删除资源
解决方法:其中一个引用weak指针对象
代码:
循环引用:
#include <iostream>
#include <memory>
class Child;
class Parent;
class Parent {
private:
std::shared_ptr<Child> ChildPtr;
public:
void setChild(std::shared_ptr<Child> child) {
this->ChildPtr = child;
}
void doSomething() {
if (this->ChildPtr.use_count()) {
}
}
~Parent() {
}
};
class Child {
private:
std::shared_ptr<Parent> ParentPtr;
public:
void setPartent(std::shared_ptr<Parent> parent) {
this->ParentPtr = parent;
}
void doSomething() {
if (this->ParentPtr.use_count()) {
}
}
~Child() {
}
};
int main() {
std::weak_ptr<Parent> wpp;
std::weak_ptr<Child> wpc;
{
std::shared_ptr<Parent> p(new Parent);
std::shared_ptr<Child> c(new Child);
p->setChild(c);
c->setPartent(p);
wpp = p;
wpc = c;
std::cout << p.use_count() << std::endl; // 2
std::cout << c.use_count() << std::endl; // 2
}
std::cout << wpp.use_count() << std::endl; // 1
std::cout << wpc.use_count() << std::endl; // 1
return 0;
}
正确引用:
#include <iostream>
#include <memory>
class Child;
class Parent;
class Parent {
private:
//这里改为引用weak
//std::shared_ptr<Child> ChildPtr;
std::weak_ptr<Child> ChildPtr;
public:
void setChild(std::shared_ptr<Child> child) {
this->ChildPtr = child;
}
void doSomething() {
//new shared_ptr
if (this->ChildPtr.lock()) {
}
}
~Parent() {
}
};
class Child {
private:
std::shared_ptr<Parent> ParentPtr;
public:
void setPartent(std::shared_ptr<Parent> parent) {
this->ParentPtr = parent;
}
void doSomething() {
if (this->ParentPtr.use_count()) {
}
}
~Child() {
}
};
int main() {
std::weak_ptr<Parent> wpp;
std::weak_ptr<Child> wpc;
{
std::shared_ptr<Parent> p(new Parent);
std::shared_ptr<Child> c(new Child);
p->setChild(c);
c->setPartent(p);
wpp = p;
wpc = c;
std::cout << p.use_count() << std::endl; // 2
std::cout << c.use_count() << std::endl; // 1
}
std::cout << wpp.use_count() << std::endl; // 0
std::cout << wpc.use_count() << std::endl; // 0
return 0;
}