首页 > 编程语言 >C++语言学习08

C++语言学习08

时间:2023-09-04 21:00:29浏览次数:45  
标签:语言 指向 08 C++ 内存 shared 异常 ptr 指针

一、智能指针
常规指针的缺点:
当一个常规指针离开了作用域时,只有该指针变量本身占用的内存空间(4/8字节)会被释放,
而它指向的内存空间不会自动释放,当free\delete\delete[]语句忘记执行或者无法执行,
形成内存泄露
(如何定位哦内存泄露、如何预防内存泄露)

智能指针的优点:
    智能指针本质上是一个封装了常规指针的类类型对象,并且重载了*和->运算符,使用起来与常规指针
    相近
    当智能指针离开作用域时,它的析构函数必定执行,从而在析构函数中执行释放常规指针的操作,这样
    就做到了自动释放的效果,从而避免内存泄露

    智能指针是一个类模版

C++的STL中提供了四种智能指针:auto_ptr\shared_ptr\unique_ptr\weak_ptr,在C++98标准中
只有第一个auto_ptr,C++11只支持后三个,第一个被弃用,使用会产生警告,需要提供头文件<memory>

1、auto_ptr
    采用独占拥有模式,不能同时有多个auto_ptr指向同一个内存,也就是意味着只能有一个auto_ptr
    指向同一内存区域,当另一个auto_ptr指向该内存时,原本的auto_ptr对该内存的控制权
    ,但是不能完全实现,有时候会指向同一个内存,有隐患
    auto_ptr<int> p1(new int(123));
    auto_ptr<int> p2;   //可以悬空
    p2 = p1;    //允许,但是p1转移所有权给p2,p1可能变成空指针
    *p1;   //可能段错误
    注意:这种独占式不一定成立,p1是否转移给p2不确定(当进行拷贝构造或者拷贝赋值,可能会指向同一个内存)

    使用格式:
        1、auto_ptr<类型> 对象名(new 类型名);
        2、类型* p = new 类型;
            auto_ptr<类型> 对象名(p);

2、unique_ptr  独享指针
 是auto_ptr 的升级,完全实现独占式拥有模式,保证同一时间中只有一个unique_ptr
 指向某个内存
 通过把拷贝构造、拷贝赋值函数声明为delete来实现不能给另一个unique_ptr对象赋值
 的效果
    unique_ptr<int> p1(new int)
    unique_ptr<int> p2;
    p2 = p1;    //会报错
    p2 = unique_ptr<int>(new int)//允许指向匿名unique_ptr对象的内存

    可以通过c++的全局函数 move()来转移内存的指向给另一个unique_ptr
    p2 = move(p1);    //让p2指向p1原来的内存,p1一定会变成空指针,p2在改变指向之前,会先释放自己原来的内存

3、shared_ptr   共享指针
    采用共享的拥有模式,可以允许多个shared_ptr指向相同内存
    当一个内存被shared_ptr指向时,内部有一个引用计数器+1
    当指向该内存的某个shared_ptr离开作用域、改变指向还有使
    用reset()时,引用计数器会-1当该内存的引用计数器被减为0时,
    由最后一个离开的shared_ptr在结束前释放该内存

    相关的成员函数:
        get()   获取指向内存的地址编号
        use_count()     获取引用计数器的值
        unique()        判断指向的内存是否只有一个shared_ptr指向
                        0 表示不独占     1表示独占
        reset()         放弃对内存的指向,计数-1
    全局函数:
        val2 = move(val1)   移动val1的值和使用权给val2
        swap()  交换俩个对象

    shared_ptr的循环引用问题:
        当两个类(A B)中都有可以指向对方类型的shared_ptr智能指针成员变量(pB pA)
        并且在类外通过shared_ptr指向new出来的两个类对象(pa指向类A pb指向类B),
        并且让他们的成员变量pB pA 指向对方,此时会构成循环引用,导致就算类对象
        pa pb销毁,但它们指向的对象的引用计数也无法减为0(pA pB还在指向),导致
        无法释放对象内存,导致内存泄露

4、weak_ptr 弱引用指针
    weak_ptr是为了配合shared_ptr而引入的一种智能指针,它指向一个由shared_ptr管理的
    对象而不影响该对象的生命周期,也即是将一个weak_ptr指向一个shared_ptr对象,或者离
    开时都不会改变该对象的引用计数,只有当最后一个shared_ptr离开该对象才销毁

    weak_ptr更像是shared_ptr的一个助手,而不是独立的智能指针,因此当发生shared_ptr的
    循环引用产生死锁时,可以把其中一个类的shared_ptr成员变量改为weak_ptr,即可避免产生死锁

二、异常处理
程序的错误大致分三种:
语法错误、逻辑错误、运行时错误
运行时错误发生在程序运行期间发生的问题:除零、内存分配失败、非法访问内存、
文件不存在、数组越界
C++异常处理机制就是为了解决运行时错误而引用的
C语言中运行时错误如果不管,系统会执行默认操作,可能会让程序终止产生程序崩溃,
也可能不终止,但是运行结果不正确
C++提供的异常处理机制,能够捕捉到运行时错误,至少提供了告诉调用者发生了什么事情
导致终止的方式,然后再终止

三、如何抛出异常
throw 数据
//数据可以是任意类型
//不要抛出局部变量的地址,因为该地址有可能被释放
//抛出的数据不是直接传递给捕获的变量,而是先创建一个匿名对象存储该数据,然后传递给该匿名对象

四、如何捕获异常
try{
// 可能会产生异常的代码或函数调用
}catch(类型& 变量名){
//如果使用 类型 变量名 方式捕获异常,会对匿名对象再拷贝一次,浪费资源时间,所以一般使用引用获取该
//匿名对象,可以减少一次拷贝
// 进行异常处理
}catch(类型2& 变量名){

}...

五、异常说明(异常规范)
返回值 函数名(形参列表)[异常说明 throw (类型名1,类型名2)]
{

}
例如:
void func(void)throw(类型1,类型2)
void func(void)throw()  //  表示不抛异常
异常说明:相当于该函数的限制或承诺,只抛出说明过异常类型,如果抛出说明外的类型,
可以抛出,但是不能接住
但是不同编译器对异常说明的实现不同,有的听从,有的不听从,异常说明是C++98一项功能,
C++后就抛弃了,不建议使用
C++中使用
    void func(int x) noexcept 替代

六、标准异常
C++已经定义好的异常类,当对应的异常发生时,会自动的抛出定义好的对应的异常类对象

std::exception  所有标准异常类的父类,能够捕获所有的标准异常
std::bad_alloc  new分配内存失败时抛出的异常
std::bad_array_new_length 是它的子类 new分配内存数量有误会抛出
std::bad_cast   该异常提供dynamic_cast抛出
    需要 #include <typeinfo>
std::bad_typeid 该异常可以通过typeid抛出,
    当获取具有多态属性的类型指针解引用的类型时,如果不能确定解引用后是哪个类型时,会
    抛出该异常
    Base* b = new Base;
    Base* b1 = new Son;
    Base* b2 = NULL;
    typeid(*b)  //类型 Base
    typeid(*b1) //类型 Son
    typeid(*b2) //抛出异常

七、自定义异常类
通过设计一个继承了exception的异常类,可以个性化地抛出想要的异常
#define ZZERROR(...) ZZError(TIME,FILE,func,LINE,VA_ARGS)

class ZZError : public exception
{
    string time;
    string file;
    string func;
    size_t line;
    string error;
public:
    ZZError(const string& time,const string& file,const string& func,size_t line,const string& error):time(time),file(file),func(func),line(line),error(error){}
    ~ZZError(void){}

    const string& what(void)
    {
        return error;
    }

    friend ostream& operator<<(ostream& os,const ZZError& err)
    {
        return os << "time:" << err.time << " file:" << err.file <<" func:" << err.func << " line:" << err.line << " error:" << err.error;
    }
};

八、使用异常需要注意的问题
1、不要抛出局部变量、对象地址,而是抛出变量、对象本身
2、建议使用引用的方式来捕获异常,减少一次拷贝
3、不要在构造函数、析构函数中抛出异常
4、在捕获异常时,先捕获子类类型,再捕获父类类型

标签:语言,指向,08,C++,内存,shared,异常,ptr,指针
From: https://www.cnblogs.com/c-learnmore/p/17678080.html

相关文章

  • C++11——3.21-3.22 move,forward
    ★★★原文链接★★★:https://subingwen.cn/cpp/move-forward/3.21move资源的转移3.22forward完美转发3.21move资源的转移move方法可以将左值转换为右值使用这个函数并不能移动任何东西,它将一个对象的所有权从这个对象转移到另一个对象,只是转移,没有内存拷贝。move语......
  • MySQL入门系列1-数据定义语言(DDL)
    一、概念DDL:数据定义语言,用来定义数据库对象,包含数据库、数据表、数据表中的字段。二、数据库相关操作1.查询所有数据库showdatabases;2.查询当前所在的数据库selectdatabase();3.创建数据库createdatabaseifnotexists数据库名;4.删除数据库dropdatabase数据库名;5.切换......
  • 如何通过C++开发高效的机器人控制程序
    如何通过C++开发高效的机器人控制程序导语:随着人工智能和机器人技术的不断发展,机器人控制程序的开发变得越来越重要。本文将介绍如何使用C++语言开发高效的机器人控制程序,并提供一些代码示例。一、了解机器人的控制原理在开始开发机器人控制程序之前,首先需要了解机器人的控制原......
  • 《c++高级编程》笔记--内存管理
    作者:fbysss关键字:C++内存管理《c++高级编程》笔记1.new关键字使用关键字new时,内存是在堆(heap)里分配的,不使用new,内存是在堆栈(stack)分配的。句柄handle一般用来描述一个指针的指针。之所以使用“句柄”,是因为句柄允许底层软件在必要时移动内存。使用new的时候,会返回一个指针,并且......
  • WPF项目国际化多语言工具ResXManager使用
    首先在VS的扩展找到ResXManager进行下载安装如果安装提示:vsix安装提示无法成功应用某些修改找到安装程序实例1a5a9225,但其处于不可启重新选中工具进行安装之后即可(有可能之前选中安装了,但是功能不完整,重新点击安装完整即可) 安装完ResXManager之后打开新增语言,然后导出,给......
  • C++11——3.17-3.20 右值引用
    ★★★原文链接★★★:https://subingwen.cn/cpp/rvalue-reference/3.17.右值和右值引用3.18.右值引用的作用以及使用3.19.未定引用类型的推导3.20.右值引用的传递3.17.右值和右值引用左值,lvalue,locatorvalue,(locator:定位器)右值,rvalue,readvalue,(read:只读)右值分为纯......
  • 【校招VIP】前端JavaScript语言之跨域
    考点介绍:什么是跨域?浏览器从一个域名的网页去请求另一个域名的资源时,域名、端口、协议任一不同,都是跨域。跨域是前端校招的一个重要考点,在面试过程中经常遇到,需要着重掌握。本期分享的前端算法考点之大数据相关,分为试题、文章以及视频三部分。答案详情解析和文章内容可点击下方......
  • 自然语言工具包(Natural Language Toolkit,简称NLTK) 简介
    自然语言工具包(NaturalLanguageToolkit,简称NLTK)是一个广泛使用的Python库,用于处理和分析自然语言文本。它提供了各种工具和数据集,用于文本预处理、语言模型、词性标注、句法分析、语义分析、情感分析、文本分类等自然语言处理任务。以下是NLTK的一些主要功能和特点:1.丰富的语......
  • Linux 服务器下C++开发找不到mysql.h
    问题背景腾讯云服务器,linuxcentOS7内核,mysql版本5.5为宝塔腾讯云版自动安装C++用cmake编译时找不到mysql.h解决1.首先尝试yum安装mysql-devel包,但是yum让我直接下载了mariadb相关的包,下载时它,与原有包冲突bt-mysql55-5.5.62-1.el7.x86_64,但是删除原有包后mysql启动有问......
  • Java语言基础知识全总结
    一.Java的优点1.      跨平台性。一次编译,到处运行。Java编译器会将Java代码编译成能在JVM上直接运行的字节码文件,C++会将源代码编译成可执行的二进制代码文件,所以C++执行速度快2.      纯面向对象。Java所有的代码都必须在类中书写。C++兼具面向对象和面向过程的特......