设为首页收藏本站
查看: 345|回复: 6

8.《剑指C++》之从C到C++(8)

[复制链接]
  • TA的每日心情
    擦汗
    昨天 08:01
  • 签到天数: 760 天

    [LV.10]以坛为家III

    发表于 2020-6-13 11:57:27 | 显示全部楼层 |阅读模式
    本帖最后由 御天行 于 2020-6-14 14:13 编辑

    ======《剑指C++系列》:总目录======

    本讲主要介绍:C++中的newdelete
    C语言中提供了malloc和free两个系统级别函数,完成对堆内存的申请和释放。而在C++中,则提供了两个关键字new和delete。用这两个关键字,实现对堆内存的申请与释放。
    1.new和new[]--申请空间
    申请单变量空间
    new 后面直接跟类型即可,比如 new int,申请一个 int 类型空间的大小,int int(10)后面括号里面跟的是初始化的值。
    1. #include <iostream>
    2. using namespace std;

    3. struct Stu{
    4.     int a;
    5.     char b;
    6.     short c;
    7. };

    8. int main()
    9. {
    10.     //C语言写法
    11.     //int *p = (int *)malloc(sizeof(int));
    12.    
    13.     //C++写法
    14.     int *p1 = new int;
    15.     int *p2 = new int(10);  //括号中可初始化值
    16.    
    17.     Stu *p3 = new Stu;
    18.     Stu *p4 = new Stu{4,'a',1};  //对结构体和数组的初始化要用大括号
    19.    
    20.     return 0;
    21. }
    复制代码

    申请一维或多维数组
    new 关键字,后面跟上类型和维度,比如申请一个 10 个 int 类型大小的数组,即 new int[10], 后面也可以跟初始化数据。
    1. #include <iostream>
    2. using namespace std;

    3. int main(){

    4.     //申请一维数组空间
    5.     float *p1 = new float [10];
    6.     float *p2 = new float [10]{1.2,2.3,3.4}; //初始化

    7.     //申请二维数组空间
    8.     int (*p3)[3] = new int[2][3];
    9.     int (*p4)[3] = new int[2][3]{{1,2},{3}};//初始化

    10.     //申请三维数组空间
    11.     int (*p5)[3][4] = new int[2][3][4];
    12.     int (*p6)[3][4] = new int[2][3][4]{{1}};

    13.     return 0;
    14. }
    复制代码

    申请指针数组
    1. #include <iostream>
    2. using namespace std;

    3. int main(){

    4.     char **p = new char *[5];
    5.     p[0] = "Hellow";
    6.     p[1] = "Honker";
    7.     p[2] = "China";
    8.     p[3] = "Huawei";
    9.     p[4] = "Apple";

    10.     for (int i=0;i<5;i++) {
    11.     cout<<p[i]<<endl;
    12.     }

    13.     return 0;
    14. }
    复制代码

    2.delete和delete[]--释放空间
    对于申请的单变量空间,采用 delete 后面跟指针即可,比如 delete p; 对于一维或是多维数组一律采用 delete[]。
    1. #include <iostream>
    2. using namespace std;

    3. int main(){

    4.     int *i = new int;
    5.     char *p1 = new char[3];
    6.     char (*p2)[3] = new char[2][3];
    7.     char **p3 = new char *[5];

    8.     delete i;
    9.     delete[] p1;
    10.     delete[] p2;
    11.     delete[] p3; //释放数组,统一用delete[]即可;

    12.     return 0;
    13. }
    复制代码

    =================================以下内容仅做了解====================================
    3.返回值判断
    对于 malloc 申请出的空间,类型是 void*型,如果申请失败,则返回 NULL,可以通过过返值对申请成功与否作过判断。
    new 申请空间失败不是返回 NULL,而是抛出异常(后面的章节会详细叙述),应当采用 try catch 结构对其处理。当然也我们可以采用不抛出异常的方式,此时用法同malloc。
    失败退出测试
    为了测试申请失败的情况,我们申请了一个大内存(视个人电脑内存容量而定)。
    实验1:内存申请测试
    1. #include <iostream>
    2. using namespace std;

    3. int main(){

    4.     double * p[50];

    5.     for (int i=0; i<50; i++){
    6.         p[i] = new double[10000000];

    7.         if(p[i] == nullptr){
    8.             cout<<"new error !"<<endl;
    9.         }
    10.         cout<<i<<endl;
    11.     }
    12.     cout<<"Hellow Worle"<<endl;

    13.     return 0;
    14. }
    复制代码

    分别验证成功和失败的状况:



    异常机制try catch
    由上述案例可知,当申请失败的时候,我们设置的判断机制未能生效,这是由于,C++与C不同,当申请失败的同时,直接抛出异常,中断程序,因此无法执行到下面的if函数。
    在C++中有一套异常处理机制。下面我们采用try catch的方案来解决申请失败的情况。
    将可能会申请失败的代码段放置到 try 块中,然后在紧随其后的 catch 块中捕获失败。(对于此案例,仅做了解,即可,后续会深入探究C++的异常处理机制)
    我们对实验1的代码进行以下改造:
    1. #include <iostream>
    2. using namespace std;

    3. int main(){

    4.     double * p[50];

    5.     try {

    6.         for (int i=0; i<50; i++){

    7.             p[i] = new double[10000000];
    8.             cout<<i<<endl;
    9.         }
    10.     } catch (bad_alloc &e) {
    11.         cout<<e.what()<<endl;
    12.     }

    13.     return 0;
    14. }
    复制代码

    运行结果如下:

    设置回调 set_new_handlertry catch
    除了采用上述方式以后,还可以设置,申请失败回调的方法。设置回调的函数为set_new_handler。
    1. #include <iostream>
    2. #include<new>
    3. using namespace std;

    4. void newError(){
    5.     cout<<"New Error !"<<endl;
    6.     exit(-1);
    7. }

    8. int main(){

    9.     double * p[50];

    10.     set_new_handler(newError);

    11.     for (int i=0; i<50; i++){

    12.         p[i] = new double[10000000];
    13.         cout<<i<<endl;
    14.     }

    15.     return 0;
    16. }
    复制代码

    运行结果如下:

    可以在 new 和类型之间加(nothrow)关键字,此时申请失败是不会抛出任何的异常的,其行为等同于 malloc。
    1. //实验1改进版:增加nothrow关键字及头文件<new>,其他无改动
    2. #include <iostream>
    3. #include<new>
    4. using namespace std;

    5. int main(){

    6.     double * p[50];

    7.     for (int i=0; i<50; i++){
    8.         p[i] = new (nothrow)double[10000000];

    9.         if(p[i] == nullptr){
    10.             cout<<"new error !"<<endl;
    11.             break;
    12.         }
    13.         cout<<i<<endl;
    14.     }
    15.     cout<<"Hellow World"<<endl;

    16.     return 0;
    17. }
    复制代码


    new和delete的使用规则
    1.new/delete关键字,底层仍旧是以malloc和free实现的。但效率高于这两个函数。
    2.配对使用:避免内存泄露和多重释放。
    3.避免交叉使用:比如malloc申请空间,用delete释放;new申请空间,用free释放。

    C++为什么引入new的delete
    如果只是以上的功能,c 中的 malloc 和 free 完全可以胜任,C++就没有必要更进一步,引入这两个关键字。
    此两关键字,重点用在类对象的申请与释放。申请的时候会调用构造器完成初始化,释放的时候,会调用析构器完成内存的清理。(这将在之后C++面向对象部分进行介绍)
    上一篇:7.C++之引用(下)
    下一篇:9.内联函数inline

    本帖子中包含更多资源

    您需要 登录 才可以下载或查看,没有帐号?注册

    x
  • TA的每日心情
    开心
    7 天前
  • 签到天数: 94 天

    [LV.6]常住居民II

    发表于 2020-6-13 12:33:38 | 显示全部楼层
    看不懂,可以说详细点吗?
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    开心
    昨天 12:21
  • 签到天数: 1463 天

    [LV.10]以坛为家III

    发表于 2020-6-13 13:01:58 | 显示全部楼层
    感谢楼主分享,楼主辛苦!
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    擦汗
    昨天 08:01
  • 签到天数: 760 天

    [LV.10]以坛为家III

     楼主| 发表于 2020-6-13 14:34:19 | 显示全部楼层
    吴宇锋 发表于 2020-6-13 12:33
    看不懂,可以说详细点吗?

    关于后半部分的异常处理机制,后续会有详细的介绍,这里了解一下概念即可。
    回复 支持 反对

    使用道具 举报

  • TA的每日心情

    2020-7-21 21:03
  • 签到天数: 92 天

    [LV.6]常住居民II

    发表于 2020-6-13 16:04:52 | 显示全部楼层
    多谢楼主分享,期待楼主分享更多精彩
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    开心
    7 天前
  • 签到天数: 94 天

    [LV.6]常住居民II

    发表于 2020-6-15 22:04:44 | 显示全部楼层
    御天行 发表于 2020-6-13 14:34
    关于后半部分的异常处理机制,后续会有详细的介绍,这里了解一下概念即可。

    好的,谢谢你的分享和回复我
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    开心
    4 天前
  • 签到天数: 10 天

    [LV.3]偶尔看看II

    发表于 2020-7-1 10:10:12 来自手机 | 显示全部楼层
    学习了 感谢楼主分享
    回复 支持 反对

    使用道具 举报

    您需要登录后才可以回帖 登录 | 注册

    本版积分规则

    关闭

    站长推荐 上一条 /3 下一条

    红盟社区--中国红客联盟 

    Processed in 0.121060 second(s), 19 queries.

    站点统计| 举报| Archiver| 手机版| 黑屋 |   

    Powered by HUC © 2001-2017 Comsenz Inc.

    手机扫我进入移动触屏客户端

    关注我们可获取更多热点资讯

    Honor accompaniments. theme macfee

    快速回复 返回顶部 返回列表