10分钟掌握C++中的智能指针和异常处理

一、智能指针

常规指针的缺点:

当一个常规指针离开了作用域时,只有该指针变量所占用的内存空间(4字节/8字节)被释放,而它所指向的内存空间不会被释放,当free\delete\delete[] 语句无法执行或者忘记执行时就会导致内存泄露

智能指针的优点:

智能指针是一个封装了常规指针的类类型对象,封装了 * -> 运算符
当智能指针离开了作用域时,它的析构函数就会自动执行,析构函数中执行了常规指针的释放操作,从而做到了自动释放内存的效果,避免了内存泄露

智能指针与常规指针的相同点:

智能指针虽然是类对象,但是它重载了* -> ,因此在使用时可以像常规指针一样使用

C++STL中提供了四个智能指针:

auto_ptr \ unique_ptr \ shared_ptr \ weak_ptr

其中C++98只有第一个,C++11中只支持后三个,第一个被弃用了,使用会产生警告
需要提供头文件 < memory >

1、auto_ptr

采用独占式拥有模式,不能同时有多个auto_ptr指向同一个资源,但是又不能完全限制指向操作,因此有隐患,并且不能放入容器

auto_ptr<类型> p1(new 类型(初始值));
cout << *p1 << endl;    //访问内存
auto_ptr<类型> p2;
p2 = p1;    //不报错,p1转移所有权给p2
cout << *p1 << endl;    //空指针解引用

2、unique_ptr 独享指针

相当于auto_ptr的升级版本,完全实现了独占式拥有模式,保证同一时间内只有一个unique_ptr指向某一个资源,通过把拷贝构造函数、赋值操作函数声明为delete来实现无法转移的效果

unique_ptr<类型> p1(new 类型(初始值));
cout << *p1 << endl;    //访问内存
unique_ptr<类型> p2;
p2 = p1;    //报错
p2 = unique_ptr<string>(new string("xixi"));    //不报错,允许临时对象的赋值
unique_ptr<string> p3;
p3 = move(p1);  //p1NULL p3指向原p1内存

注意:如果想要转移使用权,可以使用C++标准库move进行

3、shared_ptr 共享指针

采用共享式拥有模式,让多个shared_ptr同时指向相同资源

当shared_ptr指向某个资源时,在内部有资源的一个引用计数,并且+1
当有别的shared_ptr指向该资源时,原来的引用计数+1
当一个shared_ptr离开了作用域时,所指向的资源的引用计数-1,并放弃指向
或者当调用了reset成员函数时,放弃指向资源,引用计数-1
当该资源的引用计数为0时,最后一个shared_ptr在结束前自动释放资源内存
相关成员函数:
use_count() 返回引用计数的数量
unique()    返回是否独占资源
reset()     放弃对资源的指向
swap()      标准库函数,交换两个指针的指向
get()       返回内部对象(指针)
shared_ptr的循环引用问题:

当有两个类,都有可以指向对方类型的共享指针成员变量时,并且在类外分别通过另外两个共享指针指向new出来的这两个类对象,并且让它们内部的共享指针成员变量分别指向对方类对象,此时就构成了shared_ptr的循环引用死锁,无论如何都无法调用两个类对象的析构函数,导致内存泄露

4、weak_ptr 弱引用指针

weak_ptr是为了配合shared_ptr而引入的一种智能指针,它指向一个由shared_ptr管理的资源,但是不影响该资源的生命周期,也即是weak_ptr指向一个由shared_ptr管理的资源时,shared_ptr的引用计数不会改变
无论是否有weak_ptr指向,一旦指向资源的shared_ptr计数为0,资源就释放,weak_ptr更像是shared_ptr的助手
因此当shared_ptr因为循环引用产生死锁问题时,把其中一个类的shared_ptr成员变量变为 weak_ptr 即可解决问题

二、C++的异常处理

1、什么是异常:

当代码出错时,停止执行,返回一个数据
C语言中调用者只能通过使用、接收返回值的方式处理错误、异常
C++中可以接收自己返回或者系统返回的返回值,根据返回数据的类型,从而则执行不同的错误、异常处理语句

2、如何抛异常

 throw 数据;

数据可以是任何类型,不要去抛局部变量的地址或引用

3、如何捕获异常

try{
    //可能会产生异常的代码或者函数调用
}catch(类型名& 变量名){
    //处理错误
}

4、异常说明

返回值 函数名(参数列表) throw(类型1,类型2,...)
{

}

异常说明相当于该函数的限制或者承诺,只能抛出说明过的异常类型,如果函数抛出了异常说明外的异常类型,运行时无法捕获并会产生运行错误

5、标准异常

C++中已经定义好的异常类,当对应的异常发生后,会自动抛出定义好的异常类对象

exception 该异常是所有标准C++异常的父类,能捕获所有的标准异常
bad_alloc 该异常可以通过 new 抛出(内存不够),如果时C++11,会抛出它子类std::bad_array_new_length
bad_cast 该异常可以通过 dynamic_cast 抛出
bad_exception 这在处理 C++ 程序中无法预期的异常时非常有用
bad_typeid 该异常可以通过 typeid 抛出
logic_error 理论上可以通过读取代码来检测到的异常

6、自定义异常类

class YHError
{   
    string time;
    string file;
    string func;
    size_t line;
    string erro;
public:
    YHError(const string& time,const string& file,const string& func,const size_t& line,const string& erro):time(time),file(file),func(func),line(line),erro(erro) {}
};

7、使用异常需要注意的问题

1、不要返回局部变量、对象的地址,但可以返回临时对象
2、建议都用引用的方式进行捕获异常,否则会构造、拷贝两次
3、不要在构造函数、析构函数抛异常
4、如果存在父子类异常,先捕获子类类型,再捕获父类类型
内存泄漏(Memory Leak)指的是程序中已经分配的内存未被释放或者无法释放,导致系统内存的浪费。内存泄漏的结果可能是程序运行减慢甚至系统崩溃等后果。一些常见的内存泄漏情况包括:分配一个内存块并使用其中未经初始化的内容;释放一个内存块,但继续引用其中的内容;子函数中分配的内存空间在主函数出现异常中断时或主函数对子函数返回的信息使用结束时,没有对分配的内存进行释放;程序实现过程中分配的临时内存在程序结束时没有释放临时内存。内存泄漏一般是不可再现的,开发人员不易在程序调试测试阶段发现,即使花费了很多精力时间,也无法彻底消除。 空指针(Null)是指针初始化为Null,与未初始化的值不同。当一个指针被初始化为Null时,它指向的是一个无效的地址,也就是没有实际对象的地址。在使用一个空指针时,由于它指向无效的地址,可能会导致程序出错或崩溃。 在编程中,野指针(Wild Pointer)指的是指针指向的地址是随机的、未知的或者无效的。它通常是由于指针未正确初始化或指针指向的对象已经被释放而产生的。当使用野指针时,由于指针指向的地址是不确定的,可能会导致程序运行出错或崩溃。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [空指针指针 内存泄漏 内存溢出](https://blog.youkuaiyun.com/heneyT/article/details/119681009)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [OC野指针指针,僵尸对象内存泄露](https://blog.youkuaiyun.com/weixin_29692653/article/details/117116086)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值