C++基础篇 第七天 异常、智能指针、nullptr,auto

news2024/11/24 8:41:13

目录

异常

异常概念:

C和C++中异常的区别

异常处理

1. throw抛出异常

2. try...catch 进行异常处理

3.try...catch抛出自建类的异常

4.自建类的异常延伸

捕获的扩展

提高异常捕获的概率

智能指针

auto_ptr(已废弃,只做了解)

auto_ptr智能指针的方法

弃用原因(了解):

unique_ptr

shared_ptr

weak_ptr

nullptr

auto 自动推导(基础)



异常

异常概念:

C++的异常是指程序在运行期间出现的问题,编译可以通过,说明代码出现了逻辑问题,而不是语法问题。当程序运行的过程中出现了C++标准库中预定义的异常现象时,程序会抛出一个异常对象,此对象需要正确地处理,否则会导致运行终止。

C和C++中异常的区别

1. 异常的语法:C++中具有原生的异常处理机制,使用`try-catch`块来捕获和处理异常。而C语言并没有内置的异常处理机制,需要使用其他方式来处理错误,如返回错误码、使用全局变量等。

2. 异常类型:C++中的异常可以是任何类型的对象,包括内置类型、自定义类型、标准库类型等。而C语言中没有内置的异常类型概念,错误通常以错误码或特定的返回值表示。

3. 异常的传播:在C++中,异常可以在调用栈上进行传播,即从抛出异常的地方一直传播到能够处理异常的地方。而在C语言中,错误处理通常是通过返回错误码或特定值来传递的。

4. 异常处理的开销:由于C++中的异常处理机制涉及到对象的构造和析构、栈的展开等操作,因此异常处理可能会带来一定的性能开销。而C语言中的错误处理通常更加轻量级,不会引入额外的开销。

#include <iostream>
using namespace std;
int main()
{
    string s="hello";
    cout<<s.at(0)<<endl;
    cout<<s.at(10)<<endl; 
    cout<<"程序继续运行。。"<<endl;
}

正确的捕获方式

#include <iostream>
#include <stdexcept>
using namespace std;

int main()
{
    string s="hello";
    cout<<s.at(0)<<endl;
    try{
        cout<<s.at(10)<<endl;
    }catch(out_of_range a){
        cout<<a.what()<<endl;
    }
    cout<<"程序继续运行。。"<<endl;
}

异常处理

1. throw抛出异常

可以抛出任意类型的异常,抛给程序调用者,如果出现异常,调用者需要处理,否则程序就会终止。

#include <iostream>
using namespace std;
void division(double a,double b)
{
    if(b==0){
        throw 'e'; 
    }
    cout<<a/b<<endl;
}
int main()
{
    double a=3;
    double b=2;
    division(a,b);
    b=0;
    division(a,b);
    cout<<"程序继续运行"<<endl;
}


2. try...catch 进行异常处理

使用try-catch代码块进行异常的捕获,try代码块表示尝试执行可能出现异常的代码,catch块表示如果try块中出现了异常,则与catch块捕获的异常类型进行匹配,如果匹配成功,则进入catch块,如果匹配失败,程序仍然终止。

#include <iostream>
using namespace std;
void division(double a,double b){
    if(b==0){
        throw 'e'; 
    }
    cout<<a/b<<endl;
}
int main()
{
    double a=3;
    double b=2;
    division(a,b);
    b=0;
    try{
        division(a,b);
    }catch(char e){
        cout<<"异常已经处理,可以继续运行"<<endl;
    }
    cout<<"程序继续运行。。"<<endl;
}

3.try...catch抛出自建类的异常

#include <iostream>
using namespace std;
class DivisionByZero{
private:
    string message;
public:
    DivisionByZero(string message){
        this->message=message;
    }
    void getMsg(){
        cout<<message<<endl;
    }
};
void division(double a,double b){
    if(b==0){
        throw DivisionByZero("你除0出现了错误!");
    }
    cout<<a/b<<endl;
}
int main()
{
    double a=3;
    double b=2;
    division(a,b);
    b=0;
    division(a,b);
    cout<<"程序继续运行。。"<<endl;
}

4.自建类的异常延伸

#include <iostream>
using namespace std;
class DivisionByZero{
private:
    string message;
public:
    DivisionByZero(string message){
        this->message=message;
    }
    void getMsg(){
        cout<<message<<endl;
    }
};
void division(double a,double b){
    if(b==0){
        //throw 'a';
        throw DivisionByZero("你除0出现了错误!");
    }
    cout<<a/b<<endl;
}
int main()
{
    double a=3;
    double b=2;
    division(a,b);
    b=0;
    try{
        division(a,b);
    }catch(DivisionByZero e){
        e.getMsg();
        cout<<"这里是处理的方式。。。"<<endl;
    }
    cout<<"程序继续运行。。"<<endl;
}

捕获的扩展


提高异常捕获的概率

1. 准确标识可能引发异常的代码块:
在编写代码时,要仔细考虑可能引发异常的地方,并将其放置在适当的`try`块中。这样可以确保异常被正确捕获,并且避免在不应该捕获异常的地方捕获它们。

2. 使用更具体的异常类型:
在抛出异常时,尽量使用更具体的异常类型,而不是通用的`std::exception`。这样可以使异常处理更加精确和灵活,以便针对不同类型的异常采取不同的处理方式。

3. 捕获异常的顺序:

在使用多个`catch`块捕获异常时,应该将最具体的异常类型的`catch`块放在前面,而将更通用的异常类型的`catch`块放在后面。这样可以确保异常被正确地捕获,并避免被更通用的异常类型所捕获。

4. 使用异常基类捕获多个异常

如果有多个异常类型具有相似的处理方式,可以使用异常基类来捕获它们。这样可以减少重复的代码,并提高异常捕获的概率。

#include <iostream>
#include <stdexcept>
using namespace std;
class DivisionByZero{
private:
    string message;
public:
    DivisionByZero(string message){
        this->message=message;
    }
    void getMsg(){
        cout<<message<<endl;
    }
};
void division(double a,double b){
    if(b==0){
        throw DivisionByZero("你除0出现了错误!");
    }
    cout<<a/b<<endl;
}
int main()
{
    double a=3;
    double b=2;
    division(a,b);
    b=0;
    try{
        division(a,b);
    }catch(const length_error e ){
        cout<<1<<endl;
    }catch(const logic_error e){
        cout<<2<<endl;
    }catch(const exception e){
        cout<<3<<endl;
    }catch(...){
        cout<<4<<endl;
    }
    cout<<"程序继续运行。。"<<endl;
}

智能指针

C++智能指针的存在可以提供自动化的内存管理、异常安全性、简化代码、防止悬空指针以及共享所有权等好处,使得C++编程更加方便、安全和高效。

智能指针主要用于管理堆内存对象的生命周期,本身指针对象是位于栈内存的对象。

智能指针需要引入头文件#include <memory> ,智能指针管理的new关键字创建的堆内存对象

auto_ptr(已废弃,只做了解)

#include <iostream>
#include <memory>
using namespace std;
class Test{
private:
    string str;
public:
    Test(string s):str(s){}
    ~Test(){
        cout<<str<<"销毁了"<<endl;
    }
};
int main()
{
    {
       Test t("A");
       Test * t2=new Test("B");
//       传统手动销毁对象内存
//       delete t2;
//       t2=NULL;
       auto_ptr <Test> ap1(t2); //智能指针自动管理
    }
}

auto_ptr智能指针的方法

#include <iostream>
#include <memory>
using namespace std;
class Test{
private:
    string str;
public:
    Test(string s):str(s){}
    ~Test(){
        cout<<str<<"销毁了"<<endl;
    }
    void show(){
        cout<<"str的值是:"<<str<<endl;
    }
};
int main()
{
    {
        //第一种构造方式
       Test * t1=new Test("B");
       auto_ptr <Test> ap1(t1); //智能指针自动管理
       //第二种构造方式
       auto_ptr <Test> ap2(new Test("C"));
       //get()方法可以得到管理的堆内存对象的地址
       cout<<ap1.get()<<" "<<t1<<endl;  //0xee17c0 0xee17c0
       ap2.get()->show(); //str的值是:C
       //reset()方法  放弃之间对象的管理权,会把之前对象的内存释放
       ap2.reset(new Test("D"));
       cout<<"------------"<<endl;
       //release()方式 释放的管理权.但是管理对象内存不会释放
       ap1.release();
       delete t1;
       t1=NULL;
    }
}

这个警告说明auto_ptr已经被废弃了

弃用原因(了解):

1. 潜在的资源所有权转移问题:`std::auto_ptr` 允许资源的所有权在拷贝或赋值时进行转移。这意味着当您将一个 `std::auto_ptr` 赋值给另一个 `std::auto_ptr` 或者将其作为函数参数传递时,原始指针的所有权会被转移给新的 `std::auto_ptr`。这可能导致潜在的所有权混乱和资源释放问题。

2. 缺乏拷贝语义:`std::auto_ptr` 不支持拷贝构造函数和拷贝赋值运算符。这意味着无法直接通过拷贝 `std::auto_ptr` 对象来创建新的对象,限制了它的使用场景。

3. 不适用于标准容器:由于 `std::auto_ptr` 的所有权转移特性,它不能与标准容器(如 `std::vector` 或 `std::map`)一起使用。将 `std::auto_ptr` 存储在容器中会导致资源的所有权混乱和未定义行为。

#include <iostream>
#include <memory>
using namespace std;
class Test{
private:
    string str;
public:
    Test(string s):str(s){}
    ~Test(){
        cout<<str<<"销毁了"<<endl;
    }
    void show(){
        cout<<"str的值是:"<<str<<endl;
    }
};
int main()
{
    {
        //第一种构造方式
       Test * t1=new Test("B");
       auto_ptr <Test> ap1(t1); //智能指针自动管理
       cout<<t1<<endl;
       cout<<ap1.get()<<endl;    //0x6e17c0

       auto_ptr <Test> ap2(ap1); //拷贝构造
       cout<<ap1.get()<<" "<<ap2.get()<<endl; //0 0x6e17c0

       auto_ptr<Test> ap3=ap2;  //隐式的拷贝构造
       cout<<ap1.get()<<" "<<ap2.get()<<" "<<ap3.get()<<endl;

       auto_ptr<Test> ap4;
       ap4=ap3;  //等号赋值
       cout<<ap1.get()<<" "<<ap2.get()<<" "<<ap3.get()<<" "<<ap4.get()<<endl;

    }
}

unique_ptr

解决了auto_ptr复制语义发生控制权转移的问题,如需转移可以使用move的方式

#include <iostream>
#include <memory>
using namespace std;
class Test{
private:
    string str;
public:
    Test(string s):str(s){}
    ~Test(){
        cout<<str<<"销毁了"<<endl;
    }
    void show(){
        cout<<"str的值是:"<<str<<endl;
    }
};
int main()
{
    {
        //第一种构造方式
       Test * t1=new Test("B");
       unique_ptr <Test> ap1(t1); //智能指针自动管理
       cout<<t1<<endl;
       cout<<ap1.get()<<endl;

       //unique_ptr <Test> ap2(ap1); //拷贝构造
       unique_ptr <Test> ap2(move(ap1));
       cout<<ap1.get()<<" "<<ap2.get()<<endl;

       //unique_ptr<Test> ap3=ap2;  //隐式的拷贝构造
       unique_ptr<Test> ap3=move(ap2);
       cout<<ap1.get()<<" "<<ap2.get()<<" "<<ap3.get()<<endl;

       unique_ptr<Test> ap4;
       //ap4=ap3;  //等号赋值
       ap4=move(ap3);
       cout<<ap1.get()<<" "<<ap2.get()<<" "<<ap3.get()<<" "<<ap4.get()<<endl;

    }
}

shared_ptr

一个资源在多个指针之间共享。

每当有一个智能指针管理资源的时候 ,使用计数加1,当一个智能智能释放管理权的时候,使用计数就减1

当使用计数的为0的时候,此时资源没有被使用,这时才会销毁

#include <iostream>
#include <memory>
using namespace std;
class Test{
private:
    string str;
public:
    Test(string s):str(s){}
    ~Test(){
        cout<<str<<"销毁了"<<endl;
    }
    void show(){
        cout<<"str的值是:"<<str<<endl;
    }
};
int main()
{
    {
        //第一种构造方式
       Test * t1=new Test("B");
       shared_ptr <Test> sp1(t1);
       cout<<sp1.get()<<endl; //0x10217c0
       cout<<sp1.use_count()<<endl; //1
       shared_ptr <Test> sp2(sp1);
       cout<<sp1.use_count()<<" "<<sp2.use_count()<<endl;//2 2

       shared_ptr <Test> sp3=sp2;
       cout<<sp1.use_count()<<" "<<sp2.use_count()<<" "<<sp3.use_count()<<endl; //3 3 3

       shared_ptr <Test> sp4=sp3;
       cout<<sp1.use_count()<<" "<<sp2.use_count()
          <<" "<<sp3.use_count()<<" "<<sp4.use_count()<<endl; //4 4 4 4

       sp4.reset(); //sp4释放管理权 使用计数减1
       cout<<sp1.use_count()<<" "<<sp2.use_count()
          <<" "<<sp3.use_count()<<" "<<sp4.use_count()<<endl;//3 3 3 0
    }
}

weak_ptr

用于解决 `shared_ptr` 的循环引用问题,并提供了对被 `shared_ptr` 管理的对象的弱引用

#include <iostream>
#include <memory>
using namespace std;
class Test {
private:
    string str;
public:
    Test(string s) : str(s) {}
    ~Test() {
        cout << str << "销毁了" << endl;
    }
    void show() {
        cout << "str的值是:" << str << endl;
    }
};

int main() {
    {
        shared_ptr<Test> sp1 = make_shared<Test>("B");
        cout << sp1.get() << endl; // 输出:0x10217c0
        cout << sp1.use_count() << endl; // 输出:1
        shared_ptr<Test> sp2 = sp1;
        cout << sp1.use_count() << " " << sp2.use_count() << endl; // 输出:2 2
        shared_ptr<Test> sp3 = sp2;
        cout << sp1.use_count() << " " << sp2.use_count() << " " << sp3.use_count() << endl; // 输出:3 3 3
        weak_ptr<Test> wp1 = sp3;
        cout << sp1.use_count() << " " << sp2.use_count() << " " << sp3.use_count() << " " << wp1.use_count() << endl; // 输出:3 3 3 3
        shared_ptr<Test> sp4 = wp1.lock();
        cout << sp1.use_count() << " " << sp2.use_count() << " " << sp3.use_count() << " " << wp1.use_count() << endl; // 输出:4 4 4 4
        sp4.reset(); // 释放 sp4 的管理权,使用计数减 1
        cout << sp1.use_count() << " " << sp2.use_count() << " " << sp3.use_count() << " " << wp1.use_count() << endl; // 输出:3 3 3 3
    }
}

nullptr

` nullptr` 是 C++11 引入的空指针常量。它是一个特殊的关键字,用于表示一个空指针。

为什么引入nullptr

在早期的 C++ 版本中,通常使用宏 `NULL` 或整数常量 0 来表示空指针。然而,这种表示方式容易引起一些问题,因为整数类型可以隐式转换为指针类型,可能会导致错误的解释。

为了解决这个问题,并提供更明确和类型安全的空指针表示,C++11 引入了 `nullptr`。它是一个特殊的关键字,表示一个空指针常量,具有明确的空指针类型。

#include <iostream>
#include <memory>
using namespace std;
void test(char * ch){
    cout<<"1"<<endl;
}
void test(int n){
    cout<<"2"<<endl;
}
int main()
{
    char * a=NULL;
    test(a);   			//1
    test(NULL); 		//2

    char * b=nullptr; 	//1
    test(b);
    test(nullptr); 		//1
}

auto 自动推导(基础)

auto不能做参数类型的推导,也不能推断表达式的类型和数组

#include <iostream>
#include <memory>
#include <map>
using namespace std;

int main()
{
    int a=10;
    auto b=10;
    cout<<a<<" "<<b<<endl;

    map<string,int> mp;
    mp.insert(pair<string,int>("age",20));
    mp.insert(pair<string,int>("height",170));
    mp.insert(pair<string,int>("weight",60));
    //map<string,int>::iterator ite=mp.begin();
    auto ite=mp.begin();
    for(;ite!=mp.end();ite++){
        cout<<ite->first<<" "<<ite->second<<endl;
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/825742.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【工具使用】git基础操作1

目录 一.拉取git代码1.首次拉取命令2.使用图形化拉取代码3.Idea 开发工具拉取代码 二.查看当前状态1.查看在你上次提交之后是否有对文件进行再次修改 三.创建分支3.1.创建分支3.2.创建分支并切换至分支3.3.提交分支至远程仓 远程没有自动创建 四.查看分支4.1.查看本地分支 当前…

智慧园区项目:数字化引领城市转型

随着科技的迅猛发展&#xff0c;智慧园区项目正日益成为城市数字化转型的关键组成部分。这些智慧园区项目借助先进的技术&#xff0c;将传统的园区升级为智能化、数字化的生态系统&#xff0c;为城市的可持续发展和人们的生活质量带来了巨大的变革。 在智慧园区项目中&#xff…

别不信,这才是交换机组网的正确打开方式

下午好&#xff0c;我的网工朋友。 俱乐部更新交换机和路由器相关技术点一直是更新得非常勤快&#xff0c;懂的朋友都懂&#xff0c;毕竟知识点太多。这不&#xff0c;前两天刚说一篇。 之前我们聊过交换机的配置命令&#xff0c;选型关键&#xff0c;配置步骤&#xff0c;部…

C语言数组笔试题(详解)

目录 插入知识&#xff1a; 一.指向函数指针数组的指针 二.回调函数 什么是回调函数&#xff1f; 三.数组笔试题 个人名片&#xff1a; &#x1f43c;作者简介&#xff1a;一名乐于分享在学习道路上收获的大二在校生&#x1f43b;‍❄个人主页&#xff1a;GOTXX &#x1f4…

概率论与数理统计复习总结2

概率论与数理统计复习总结&#xff0c;仅供笔者复习使用&#xff0c;参考教材&#xff1a; 《概率论与数理统计》/ 荣腾中主编. — 第 2 版. 高等教育出版社《2024高途考研数学——概率基础精讲》王喆 概率论与数理统计实际上是两个互补的分支&#xff1a;概率论 在 已知随机…

亚像素到底能不能提高精度

01.什么是亚像素 亚像素(Sub Pixel),是面阵摄像机的成像面以像素为最小单位。 像素中心之间的距离有几个至十几个微米不等。为了最大限度利用图像信息来提高分辨率,有人提出了亚像素概念。意思是说,在两个物理像素之间还有像素,称之为亚像素,它完全是通过计算方法得出来的。…

three.js实现vr全景图(vue)

方法: 可以利用Threejs中的立方体或者球体实现全景图功能&#xff0c;把立方体或球体当成天空盒子&#xff0c;将无缝衔接的图片贴上&#xff0c;看起来就像在一个场景中&#xff0c;相机一般放置在中央。 three.js中文网 1、立方体实现 立方体6个面要贴上6个方向的图片&…

在 React 中渲染大型数据集的 3 种方法

随着 Web 应用程序变得越来越复杂&#xff0c;我们需要找到有效的方法来优化性能和渲染大型数据集。在 React 应用程序中处理大型数据集时&#xff0c;一次呈现所有数据可能会导致性能不佳和加载时间变慢。 虚拟化是一种通过一次仅呈现数据集的一部分来解决此问题的技术&#…

AIGC产业公司简况列表

最近梳理了国内外AIGC产业链相关的公司列表&#xff0c;如下图所示&#xff1a; 出自&#xff1a;AIGC产业公司简况列表 | 秋天的童话博客

ElementUI el-table 鼠标滚动失灵的问题及解决办法

Bug&#xff1a;ElementUI el-table 鼠标滚轮下滑动失灵的情况 我测出来的这个问题条件很苛刻&#xff0c;需要达到以下几个条件才会触发&#xff1a; 1.element plus&#xff08;其他版本没试&#xff09; 2.el-table-column组件有fixed属性时 3.template标签中有el-butto…

Adobe ColdFusion 反序列化漏洞复现(CVE-2023-29300)

0x01 产品简介 Adobe ColdFusion是美国奥多比&#xff08;Adobe&#xff09;公司的一套快速应用程序开发平台。该平台包括集成开发环境和脚本语言。 0x02 漏洞概述 Adobe ColdFusion存在代码问题漏洞&#xff0c;该漏洞源于受到不受信任数据反序列化漏洞的影响&#xff0c;攻击…

赶快卸载 Navicat和DataGrip吧,阿里又开源了一款数据库神器,太炸了

Chat2DB 是一款有开源免费的多数据库客户端工具&#xff0c;支持windows、mac本地安装&#xff0c;也支持服务器端部署&#xff0c;web网页访问。和传统的数据库客户端软件Navicat、DBeaver 相比Chat2DB集成了AIGC的能力&#xff0c;能够将自然语言转换为SQL&#xff0c;也可以…

eclipse was unable to locate its companion shared library

当转移或者Copy工程时&#xff0c; eclipse was unable to locate its companion shared library eclipse.ini 里面的路径配置错误导致 --launcher.library C:/Users/**/.p2/pool/plugins/org.eclipse.equinox. launcher.win32.win32.x86_64_1.2.700.v20221108-1024 -product …

什么是数字化?数字化转型概念是怎么兴起的?

什么是数字化&#xff1f;数字化转型的概念是怎么兴起的&#xff1f;下面我将分为2部分给大家做详细讲解。 一、什么是数字化&#xff1f; 不同国家和不同行业&#xff0c;似乎对数字化转型有不同的定义。比如&#xff1a; 美国早在2003年就提出了“数字化双胞胎”的概念&…

FuncGPT来了!专注AI生成JAVA函数,五大能力ChatGPT都说好

大语言模型风靡全球&#xff0c;正加速重构各行各业。继 GPT-4 、文心一言等生成式 AI产品之后&#xff0c;代码生成工具的队伍再添新员。近日FuncGPT&#xff08;慧函数&#xff09;功能重磅上线。 作为飞算SoFlu软件机器人的一个重要组成部分&#xff0c;FuncGPT&#xff08;…

Python 程序设计入门(001)—— 安装 Python(Windows 操作系统)

Python 程序设计入门&#xff08;001&#xff09;—— 安装 Python&#xff08;Windows 操作系统&#xff09; 目录 Python 程序设计入门&#xff08;001&#xff09;—— 安装 Python&#xff08;Windows 操作系统&#xff09;一、下载 Python 安装包二、安装 Python三、测试&…

如何在Visual Studio Code中用Mocha对TypeScript进行测试

目录 使用TypeScript编写测试用例 在Visual Studio Code中使用调试器在线调试代码 首先&#xff0c;本文不是一篇介绍有关TypeScript、JavaScript或其它编程语言数据结构和算法的文章。如果你正在准备一场面试&#xff0c;或者学习某一个课程&#xff0c;互联网上可以找到许多…

Java版本工程行业管理系统源码-专业的工程管理软件-提供一站式服务 em

&#xfeff; 工程项目管理软件&#xff08;工程项目管理系统&#xff09;对建设工程项目管理组织建设、项目策划决策、规划设计、施工建设到竣工交付、总结评估、运维运营&#xff0c;全过程、全方位的对项目进行综合管理 工程项目各模块及其功能点清单 一、系统管理 1、数据…

如何开发专属花店小程序

在当今移动互联网时代&#xff0c;小程序已经成为各类企业的必备营销工具之一。对于花店来说&#xff0c;打造一个花店预约小程序&#xff0c;可以帮助提升用户体验&#xff0c;提高销售额。那么&#xff0c;如何从零开始&#xff0c;快速打造一个花店预约小程序呢&#xff1f;…

Vue3 实用的开发技巧

一、前言 Vue3已经发布很长时候了&#xff0c;官方也将默认版本切换到了vue3&#xff0c;Vue官网也发布了完善的中文文档&#xff0c;不知同志们是否已经开始使用了了呢&#xff1f;下面给大家介绍一些在开发中Vue3实用的开发技巧&#xff0c;让大家开发更加流畅。 二、开发技…