C++智能指针

智能指针主要是为了解决内存忘记释放、内存过早释放、内存多次释放等问题,从而更好地对内存进行管理。(个人理解)

传统的裸指针虽然功能强大、使用灵活,但需要全程维护,容易出错。从而引入智能指针进行管理,可以把智能指针看做对于裸指针的包装。

智能指针有四种:auto_ptr(c++98)、shared_ptr(c++11)、unique_ptr(c++11)、weak_ptr(c++11),其中auto_ptr已被unique_ptr替代,不推荐使用auto_ptr。

智能指针是一种类模板。

一、shared_ptr共享式指针

shared_ptr允许多个指针指向同一个对象(内存)。其采用引用计数的机制,每多一个shared_ptr指向该对象,引用计数加一,每少一个shared_ptr,引用计数减一。当引用计数为0时,会自动析构该对象(释放该内存)。

shared_ptr的定义形式

shared_ptr<int> 智能指针名;//智能指针是类模板,需要使用<>指定参数类型(指针指向的类型)

shared_ptr的两种初始化方式:

1.使用new初始化

一般形式:

shared_ptr<int> sptr(new int);
shared_ptr<int> sptr1(new int(10));

int *p = new int();//值初始化
shared_ptr<int> sptr2(p);//用裸指针也可以初始化,但是不推荐

2.使用make_shared()函数初始化

一般形式:

shared_ptr<int> sptr = make_shared<int>(100);//make_shared是函数模板,所以需要使用<>指定参数类型

shared_ptr<string> sptr = make_shared<string>(5, 'a');//调用string的构造函数进行string的初始化

make_shared是一种函数模板。推荐使用make_shared()进行shared_ptr的初始化,其缺点是不能自定义删除器。

shared_ptr拓展

1.use_count():返回当前shared_ptr所指内存的强引用数即shared_ptr的个数

shared_ptr<int> p1(new int(10));
shared_ptr<int> p2(p1);
weak_ptr<int> pw1(p1);
cout<<p1.use_count()<<endl;//此时返回值为2,p1所指内存有2个强引用,1个弱引用

2.reset():用于重置shared_ptr

shared_ptr<int> p1(new int(10));
p1.reset();//不带参数情况,将p1置空
p1.reset(new int(100));//带参数情况,一般输入为new出来的裸指针,此时p1指向新的内存

3.unique:判断此shared_ptr是否独占内存

        若独占,返回true,否则返回false。

shared_ptr<int> p1 = make_shared<int> (10);
if(p1.unique()) {//此只有p1一个shared_ptr指向该内存,所以unique()返回true
    cout<<"独占"<<endl;
}
else {
    cout<<"不独占"<<endl;
}

4.shared_ptr同样可以使用*解引用,方式同普通指针

5.get():返回shared_ptr中保存的裸指针

shard_ptr<int> p1 = make_shared<int> (10);
int *p = p1.get();//get()返回p1中的裸指针
cout<<*p<<endl;

6.swap():交换两个shared_ptr指向

shared_ptr<string> ps1 = make_shared<string>("hello");
shared_ptr<string> ps2 = make_shared<string>("world");
cout << *ps1 << endl << *ps2 << endl;
swap(ps1, ps2);//交换两个指针指向的对象
ps1.swap(ps2);//交换两个指针指向
cout << *ps1 << endl << *ps2 << endl;

7.删除器

        默认情况下,在内存的强引用计数减为0时,系统会调用delete()对内存进行释放。如果指定删除器,则系统会调用指定的删除器释放内存。

删除器形式一:函数

void mydeleter(int *p) {
    //代码实现
    cout<<"自定义删除器"<<endl;
    delete p;//在自定义的删除器中一定要使用delete释放内存,否则会造成内存泄漏
}

int main() {
    shared_ptr<int> p1(new int(10), mydeleter);//在参数列表中指定删除器
    p1.reset();//p1置空,系统自动调用自定义删除器释放内存

    return 0;
}

删除器形式二:lambda表达式

shared_ptr<int> ps1(new int[10], [](int *p){
    delete[] p;
});

8.使用shared_ptr维护数组时的几种方法

第一种:从C++17开始,shared_ptr的模板参数支持传入<数据类型[]>用于对于数组内存的管理,同时提供了operator[]用于对数组元素直接进行访问,在释放数组时会调用delete[]对内存进行释放。

shared_ptr<int[]> p1(new int[]{1,2,3});//模板参数传入int[]
cout<<p1[0]>>p1[1]<<p1[2];//operator[]进行数组元素进行访问
p1.reset();//系统调用delete[]进行内存释放

第二种:在C++17前,shared_ptr不支持模板参数传入<数据类型[]>,同时不支持operator[],系统在释放内存时会默认调用delete进行释放。因此当我们使用shared_ptr管理数组时,系统会在释放内存时使用delete而报错。

情况如下:

shared_ptr<int> ps1(new int[3]{1,2,3));//使用shared_ptr管理数组
cout<<ps1.get()[0]<<endl;//C++17前不支持operator[]直接访问元素,需要使用get()[index]对元素进行访问
ps1.reset()//将ps1置空后,系统会调用delete对数组内存进行释放,从而导致错误

对于这种情况有两种解决办法:

方法1:C++提供了一种标准库的类模板default_delete,可以用于数组内存的释放。可以在初始化shared_ptr时指定该删除器。

shared_ptr<int> ps1(new int[10], default_delete<int[]>());

方法2:自己定义删除器

void mydeleter(int *p) {
    delete[] p;//用delete[]释放数组内存
}

int main() {

    shared_ptr<int> ps1(new int[10], mydeleter);//指定自己定义的删除器

    return 0;

}

注意:虽然两个shared_ptr指定的删除器可能不同,但只要它们指向同一个内存,那么它们就属于同一个类型。

二、weak_ptr

weak_ptr是用来辅助shared_ptr工作的一种智能指针,它指向由shared_ptr管理的内存,但不影响内存的生存期。(weak_ptr只会增减弱引用的计数,不会增减强引用的计数)。当shared_ptr需要释放内存时,不管有没有weak_ptr指向该内存,内存都会释放。因为weak_ptr作为一种辅助性的智能指针,其不影响所指内存的生存期,所以不能保证所指内存的有效性,因此不能通过weak_ptr对内存进行管理。

weak_ptr的初始化:一般通过shared_ptr进行初始化

shared_ptr<int> ps1(new int);
weak_ptr<int> pw1(ps1);

weak_ptr常用操作

1.use_count():返回weak_ptr所指内存的强引用计数,即shared_ptr的数量

shared_ptr<int> ps1(new int);
weak_ptr<int> pw1(ps1);
cout<<pw1.use_count()<<endl;//use_count()返回该weak_ptr指向内存的强引用计数,即有多少shared_ptr指向该内存,此情况应为1

2.expired():判断weak_ptr所指内存是否过期,若内存已被释放则返回true,若未被释放则返回false

shared_ptr<int> ps1(new int);
weak_ptr<int> pw1(ps1);
cout<<pw1.expired()<<endl;//此时内存未被释放,返回false
ps1.reset();//ps1置空,内存释放
cout<<pw1.expired()<<endl;//返回true

3.reset():用法同shared_ptr

4.lock():判断weak_ptr指向内存是否被释放,若未释放,则返回指向该内存的shared_ptr,若已释放,则返回空的shared_ptr。

shared_ptr<int> ps1 = make_shared<int>(10);
weak_ptr<int> pw1(ps1);
auto ps2 = pw1.lock();//此时pw1所指内存未释放,lock()返回一个指向该内存的shared_ptr,用一个shared_ptr来接收,强引用+1

水平有限,欢迎批评指正!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值