zoukankan      html  css  js  c++  java
  • 外传篇3 动态内存申请的结果

    1.动态内存申请一定成功吗?

    (1)问题:动态内存申请一定成功吗?

    (2)常见的动态内存分配代码:

    C代码:
        
    C++代码:
        

    (3)必须知道的事实!

    • malloc函数申请失败时返回NULL

    • new关键字申请失败时根据编译器的不同

      1. 返回NULL

      2. 抛出 std::bad_alloc 异常

    (4)问题:new语句中的异常是怎么抛出来的?

    new关键字在C++规范中的标准行为

    • 在堆空间申请足够大的内存

      1. 成功:

        1. 在获取的空间中调用构造函数创建对象
        2. 返回对象的地址
      2. 失败:

        1. 抛出 std::bad_alloc 异常

    • new在分配内存时

      1. 如果空间不足,会调用全局的 new_handler() 函数

      2. new_handler() 函数中抛出 std::bad_alloc 异常

    • 可以自定义 new_handler() 函数

      1. 处理默认的new内存分配失败的情况

     

    2.new_handler() 函数

    (1)new_handler() 的定义和使用:
          

    (2)问题如何跨编译器统一new 的行为提高代码移植性

    (3)解决方案:

    • 全局范围(不推荐)

      1. 重新定义 new / delete 的实现,不抛出任何异常

      2. 自定义 new_handler() 函数,不抛出任何异常

    • 类层次范围

      1. 重载 new / delete,不抛出任何异常
    • 单次动态内存分配

      1. 使用 nothrow 参数,指明 new 不抛出异常

    编程实验1:证明存在 new_handler() 函数

    #include <iostream>
    #include <cstdlib>
    
    using namespace std;
    
    class Test
    {
        int m_value;
    public:
        Test()
        {
            cout << "Test()" << endl;
            
            m_value = 0;
        }
        
        ~Test()
        {
            cout << "~Test()" << endl;
        }
        
        void* operator new (unsigned long size)
        {
            cout << "operator new: " << size << endl;
            
            // return malloc(size);
            
            return NULL;
        }
        
        void operator delete (void* p)
        {
            cout << "operator delete: " << p << endl;
            
            free(p);
        }
        
        void* operator new[] (unsigned long size)
        {
            cout << "operator new[]: " << size << endl;
            
            return malloc(size);
        }
        
        void operator delete[] (void* p)
        {
            cout << "operator delete[]: " << p << endl;
            
            free(p);
        }
    };
    
    void my_new_handler()
    {
        cout << "void my_new_handler()" << endl;
    }
    
    void ex_func_1()
    {
        new_handler func = set_new_handler(my_new_handler);
        
        try
        {
            cout << "func = " << func << endl;
            
            if( func )
            {
                func();
            }
        }
        catch(const bad_alloc&)
        {
            cout << "catch(const bad_alloc&)" << endl;
        }
    }
    
    int main(int argc, char *argv[])
    {
        ex_func_1();
        
        return 0;
    }

    运行结果:

    [root@bogon Desktop]# g++ test.cpp
    test.cpp: In static member function ‘static void* Test::operator new(long unsigned int)’:
    test.cpp:28: warning: ‘operator new’ must not return NULL unless it is declared ‘throw()’ (or -fcheck-new is in effect)
    [root@bogon Desktop]# ./a.out 
    func = 0

    g++编译器没有设置这个全局的 new_handler() 函数bcc编译器实现了这个全局的 new_handler() 函数

    编程实验2:动态内存申请失败的结果

    #include <iostream>
    #include <cstdlib>
    
    using namespace std;
    
    class Test
    {
        int m_value;
    public:
        Test()
        {
            cout << "Test()" << endl;
            
            m_value = 0;
        }
        
        ~Test()
        {
            cout << "~Test()" << endl;
        }
        
        void* operator new (unsigned long size)
        {
            cout << "operator new: " << size << endl;
            
            // return malloc(size);
            
            return NULL;
        }
        
        void operator delete (void* p)
        {
            cout << "operator delete: " << p << endl;
            
            free(p);
        }
        
        void* operator new[] (unsigned long size)
        {
            cout << "operator new[]: " << size << endl;
            
            return malloc(size);
        }
        
        void operator delete[] (void* p)
        {
            cout << "operator delete[]: " << p << endl;
            
            free(p);
        }
    };
    
    void ex_func_2()
    {
        Test* pt = new Test();
        
        cout << "pt = " << pt << endl;
        
        delete pt;
    }
    
    int main(int argc, char *argv[])
    {
        ex_func_2();
        
        return 0;
    }

    运行结果:

    [root@bogon Desktop]# g++ test.cpp
    test.cpp: In static member function ‘static void* Test::operator new(long unsigned int)’:
    test.cpp:28: warning: ‘operator new’ must not return NULL unless it is declared ‘throw()’ (or -fcheck-new is in effect)
    [root@bogon Desktop]# ./a.out 
    operator new: 4
    Test()
    Segmentation fault (core dumped)

    g++编译器中报错:段错误。不同的编译器报错信息不同

    编程实验3:统一不同编译器动态内存申请失败后的行为

    #include <iostream>
    #include <cstdlib>
    
    using namespace std;
    
    class Test
    {
        int m_value;
    public:
        Test()
        {
            cout << "Test()" << endl;
            
            m_value = 0;
        }
        
        ~Test()
        {
            cout << "~Test()" << endl;
        }
        
        void* operator new (unsigned long size) throw()
        {
            cout << "operator new: " << size << endl;
            
            // return malloc(size);
            
            return NULL;
        }
        
        void operator delete (void* p)
        {
            cout << "operator delete: " << p << endl;
            
            free(p);
        }
        
        void* operator new[] (unsigned long size) throw()
        {
            cout << "operator new[]: " << size << endl;
            
            // return malloc(size);
            
            return NULL;
        }
        
        void operator delete[] (void* p)
        {
            cout << "operator delete[]: " << p << endl;
            
            free(p);
        }
    };
    
    void ex_func_2()
    {
        Test* pt = new Test();
        
        cout << "pt = " << pt << endl;
        
        delete pt;
        
        pt = new Test[5];
        
        cout << "pt = " << pt << endl;
        
        delete[] pt;
    }
    
    int main(int argc, char *argv[])
    {
        ex_func_2();
        
        return 0;
    }

    运行结果:

    [root@bogon Desktop]# g++ test.cpp
    [root@bogon Desktop]# ./a.out 
    operator new: 4
    pt = 0
    operator new[]: 28
    pt = 0

    显示的调用析构函数


    编程实验4:让编译器申请失败后返回空指针而不是抛出异常

    #include <iostream>
    #include <cstdlib>
    
    using namespace std;
    
    class Test
    {
        int m_value;
    public:
        Test()
        {
            cout << "Test()" << endl;
            
            m_value = 0;
        }
        
        ~Test()
        {
            cout << "~Test()" << endl;
        }
        
        void* operator new (unsigned long size) throw()
        {
            cout << "operator new: " << size << endl;
            
            // return malloc(size);
            
            return NULL;
        }
        
        void operator delete (void* p)
        {
            cout << "operator delete: " << p << endl;
            
            free(p);
        }
        
        void* operator new[] (unsigned long size) throw()
        {
            cout << "operator new[]: " << size << endl;
            
            // return malloc(size);
            
            return NULL;
        }
        
        void operator delete[] (void* p)
        {
            cout << "operator delete[]: " << p << endl;
            
            free(p);
        }
    };
    
    void ex_func_3()
    {
        int* p = new(nothrow) int[10];
        
        // ... ...
        
        delete[] p; 
        
        int bb[2] = {0};
        
        struct ST
        {
            int x;
            int y;
        };
        
        ST* pt = new(bb) ST(); // new():在指定空间上创建对象
        
        pt->x = 1;
        pt->y = 2;
        
        cout << bb[0] << endl;
        cout << bb[1] << endl;
        
        pt->~ST(); // 显示的调用析构函数
    }
    
    int main(int argc, char *argv[])
    {
        ex_func_3();
        
        return 0;
    }

    运行结果:

    [root@bogon Desktop]# g++ test.cpp
    [root@bogon Desktop]# ./a.out 
    1
    2

    编程实验:VS2010 new实现

    /***
    *new.cxx - defines C++ new routine
    *
    *       Copyright (c) Microsoft Corporation.  All rights reserved.
    *
    *Purpose:
    *       Defines C++ new routine.
    *
    *******************************************************************************/
    
    
    #ifdef _SYSCRT
    #include <cruntime.h>
    #include <crtdbg.h>
    #include <malloc.h>
    #include <new.h>
    #include <stdlib.h>
    #include <winheap.h>
    #include <rtcsup.h>
    #include <internal.h>
    
    void * operator new( size_t cb )
    {
        void *res;
    
        for (;;) {
    
            //  allocate memory block
            res = _heap_alloc(cb);
    
            //  if successful allocation, return pointer to memory
    
            if (res)
                break;
    
            //  call installed new handler
            if (!_callnewh(cb))
                break;
    
            //  new handler was successful -- try to allocate again
        }
    
        RTCCALLBACK(_RTC_Allocate_hook, (res, cb, 0));
    
        return res;
    }
    #else  /* _SYSCRT */
    
    #include <cstdlib>
    #include <new>
    
    _C_LIB_DECL
    int __cdecl _callnewh(size_t size) _THROW1(_STD bad_alloc);
    _END_C_LIB_DECL
    
    void *__CRTDECL operator new(size_t size) _THROW1(_STD bad_alloc)
            {       // try to allocate size bytes
            void *p;
            while ((p = malloc(size)) == 0)
                    if (_callnewh(size) == 0)
                    {       // report no memory
                    static const std::bad_alloc nomem;
                    _RAISE(nomem);
                    }
    
            return (p);
            }
    
    /*
     * Copyright (c) 1992-2002 by P.J. Plauger.  ALL RIGHTS RESERVED.
     * Consult your license regarding permissions and restrictions.
     V3.13:0009 */
    #endif  /* _SYSCRT */

    实验结论:

    • 不是所有的编译器都遵循C++的标准规范

    • 编译器可能重定义 new 的实现,并在实现中抛出 bad_alloc 异常

    • 编译器的默认实现中可能没有设置全局的 new_handler() 函数

    • 对于移植性要求较高的代码,需要考虑 new 的具体细节

    3.小结

    • 不同的编译器动态内存分配上的实现细节不同

    • malloc 函数在内存申请失败时返回NULL

    • new 关键字在内存申请失败时

      1. 可能返回NULL

      2. 可能抛出 bad_alloc 异常

  • 相关阅读:
    Tensorflow源码解析2 -- 前后端连接的桥梁
    Tensorflow源码解析1 -- 内核架构和源码结构
    Python保存json文件并格式化
    如何在没有https环境下使用webrtc
    github提交代码不用输入账号密码的解决方案
    使用nodeJs在本地搭建最简单的服务
    ubuntu16.04 安装 nginx 服务器
    git pull和git pull --rebase的使用
    Linux 下各个目录的作用及内容
    阿里云服务器(Ubuntu16.04 64位)远程连接
  • 原文地址:https://www.cnblogs.com/hoiday/p/10222472.html
Copyright © 2011-2022 走看看