• C++中的new


    C++中除了沿用C的alloc系列函数之外,还可以用new/new []来分配内存(这句是废话),我们在使用new这个operator的时候多是直接使用,而没有额外引用头文件。

    写C语言代码写习惯的人都会在alloc函数之后,对指针做NULL判断,以检查内存分配是否成功,那么在C++中是否也需要以同样的方式来检查内存分配是否成功呢?根据实际code验证结果,答案是new成功返回即表示内存分配成功,不需检查指针是否为NULL,但是仍然会出现内存分配失败的情况,此时需要捕捉bad_alloc这种exceptin来知晓内存分配失败,bad_alloc是在new这个C++头文件(#include <new>)中声明的。废话先说到这里,下面以两段代码来作说明

     1 #include <iostream>
     2 #include <new>
     3 #include <cstdlib>
     4 
     5 using namespace std;
     6 
     7 int main(int argc, char *arg[])
     8 {
     9     char *buffer = NULL;
    10 
    11     try
    12     {
    13         buffer = new char[90000000000ul];      // 故意分配很大的一块内存,导致操作失败
    14 
    15         cout<<"The buffer address is: "<<static_cast<void*>(buffer)<<endl;
    16     }
    17     catch (const bad_alloc &ex)
    18     {
    19         cout<<"exception: "<<ex.what()<<endl;
    20     }
    21     catch (...)
    22     {
    23         cout<<"unknown exception"<<endl;
    24     }
    25     
    26     if (NULL != buffer)
    27     {
    28         delete[] buffer;
    29     }
    30 
    31     return 0;
    32 }

    对上面的代码进行编译和运行,结果如下

    Administrator@attention /e/Code
    $ g++ stl_new.cpp -lstdc++ -o stl_new.exe
    
    Administrator@attention /e/Code
    $ ./stl_new.exe
    exception: std::bad_alloc
    
    Administrator@attention /e/Code
    $

    可以看出分配失败时,的确throw出了bad_alloc,代码catch到这个exception即可知道内存分配失败。细心看上面的代码是有#include <new>这一行的,而C++的new头文件对new这个operator声明如下

    void* operator new(std::size_t) throw (std::bad_alloc);
    void* operator new[](std::size_t) throw (std::bad_alloc);
    void operator delete(void*) throw();
    void operator delete[](void*) throw();
    void* operator new(std::size_t, const std::nothrow_t&) throw();
    void* operator new[](std::size_t, const std::nothrow_t&) throw();
    void operator delete(void*, const std::nothrow_t&) throw();
    void operator delete[](void*, const std::nothrow_t&) throw();

    其中很明显new和new[]这两个operator都被声明会throw出std::bad_alloc(入参只有size的那种,后面均指这种,不重复说明),那是不是因为引用new头文件的缘故而使用了这个特定类型的new了呢?

    经过实际代码验证,答案为“不是”,实际上代码里去掉#include <new>这一行同样是编译OK的,且运行结果也一样。由此结论如下:

    new这个operator是C++语言内置的,其本身在内存分配失败会throw出一个bad_alloc,因此我们在使用new进行内存/对象分配时,就必须使用catch来捕捉这种可能的bad_alloc来检查分配是否失败;若不做如此处理,被throw出来的bad_alloc会未在这一层被捕捉而一直向上冒泡,若我们的代码中一直不进行catch,则会一直冒泡到CRT,而CRT对这些未被捕捉异常,处理方式是调用abort()来直接结束整个程序,最终的后果便是程序异常退出。这里再罗嗦的贴一段代码来说明这一点

     1 #include <stdio.h>
     2 
     3 int main(int argc, char *argv[])
     4 {
     5     char *buffer = NULL;
     6     
     7     buffer = new char[90000000000ul];      // 故意分配很大的一块内存
     8     printf("The buffer address is: %p\n", buffer);
     9 
    10     if (NULL != buffer)
    11     {
    12         delete[] buffer;
    13     }
    14 
    15     return 0;
    16 }

    最终编译和运行结果为

    Administrator@attention /e/Code
    $ ./new.exe
    terminate called after throwing an instance of 'std::bad_alloc'
      what():  std::bad_alloc
    
    This application has requested the Runtime to terminate it in an unusual way.
    Please contact the application's support team for more information.

     对此自己的感受便是,在C++代码中使用new,应该将其包括在try{}catch(){}中,以知道分配是否成功和避免未捕捉的异常而导致程序异常退出。

    但实际实际上在非嵌入式的环境中,比如桌面环境,内存都比较充裕(加上操作系统虚拟内存机制),内存分配失败几乎是微乎其微,而导致很多的try{}catch(){}形同虚设,而使代码有些dirty。并且倘若真的是出现内存分配失败的问题,那多是意味着软已经出现了严重的错误(比如内存泄漏),就算在这里catch到本次分配失败,也对于整个系统恢复也没什么作用,因此很多代码里都是直接使用new,而没有将其包括在try{}catch(){}之中。

    对此个人感觉是还是严谨的使用try{}catch(){}为好,毕竟内存分配失败了,也算是一种错误,应该即可就对此进行捕捉处理,将错误影响范围尽可能限制在出错的位置,这样避免错误扩大,也方便debug排错。

  • 相关阅读:
    泛型类型转为DataTable类型
    FineUploader 学习笔记
    如何理解Python中的if __name__ == '__main__'
    什么是python 中的顶层代码?
    任务十三:零基础JavaScript编码(一)
    目前比较全的CSS重设(reset)方法总结(转)
    任务十二:学习CSS 3的新特性
    JS高级程序设计第三版——变量、作用域和内存问题
    任务十:Flexbox 布局练习
    任务九:使用HTML/CSS实现一个复杂页面
  • 原文地址:https://www.cnblogs.com/lanyuliuyun/p/3041476.html
Copyright © 2020-2023  润新知