72、动态内存申请的结果

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

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

c代码:int *p=(int*)malloc(10*sizeof(int));

            if(p!=NULL){//...}

c++代码:int *p=new int[10];

if(p!=NULL) {//...}

必须知道的事实:malloc函数申请失败时返回NULL值。

new关键字申请失败时(根据编译器的不同),1、返回NULL值 2、抛出std::bad_alloc异常。

new语句中的异常是怎么抛出类的?

new关键字在c++规范中的标准行为:在堆空间申请足够大的内存,

成功:在获取的空间中调用构造函数创建对象,返回对象的地址。

失败:抛出std::bad_alloc异常

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

new在分配内存时,如果空间不足,会调用全局的new_handlwe()函数,new_handler()函数中抛出std::bad_alloc异常。

可以自定义new_handler()函数,处理默认的new内存分配失败的情况。

2、如何跨编译器统一new的行为,提高代码移植性?

解决方案:全局范围(不推荐):重新定义new/delete的实现,不抛出任何异常;自定义new_handler()函数,不抛出任何异常

类层次范围:重载new/delete,不抛出任何异常。

单词动态内存分配:使用nothrow参数,指明new不抛出异常。(失败返回空指针)

证明new_handler的存在:

#include <iostream>
#include <new>  //new_handler
#include <cstdlib>
#include <exception> //异常相关的头文件
using namespace std;
class Test
{
    int m_value;
public:
    Test()
    {
        cout << "Test()" << endl;
        
        m_value = 0;
    }    
    ~Test()
    {
        cout << "~Test()" << endl;  
    }
    
    void* operator new (unsigned int 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 int size) throw()  //throw() 返回空的话,不会创建对象
    {
        cout << "operator new[]: " << size << endl;
        
        // return malloc(size);
        
        return NULL;
    }
    
    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);
    //new_handler 预定义的函数指针,设置自定义处理函数之后,原来的处理函数就作为返回值返回过来
    try
    {
    cout << "func = " << func << endl; //func=0,g++并没有全局new_handler处理函数,bcc有抛出bad_alloc异常     
        if( func )
        {
            func();
        }
    }
    catch(const bad_alloc&)
    {
        cout << "catch(const bad_alloc&)" << endl;
    }
}

void ex_func_2()
{

    Test* pt = new Test();  //重载函数如果没有throw(),g++编译器重载函数返回NULL(在空上创建对象),调用构造函数,在

                                         //空地址上调用构造函数创建对象,里边有赋值操作等价于在0地址出进行赋值,出现段错误,bcc

                                         //跟vs不会调用构造函数

    cout << "pt = " << pt << endl;    
    delete pt;    
    pt = new Test[5];    
    cout << "pt = " << pt << endl;    
    delete[] pt; 
}

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();    //把ST对象创建到bb[2]栈空间上,在指定地址上创建对象
    pt->x = 1;
    pt->y = 2;    
    cout << bb[0] << endl;
    cout << bb[1] << endl;    
    pt->~ST();  //手工调用析构函数
}

int main(int argc, char *argv[])
{
    // ex_func_1();
    // ex_func_2();
    // ex_func_3();  
    return 0;
}
试验结论:不是所有的的编译器都遵循c++的标准规范,编译器可能重定义new的实现,并在实现中抛出 bad_alloc异常,编译器的默认实现中,可能没有设置全局的new_handler()函数,对于移植性要求较高的代码,需要考虑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))  //内部设置new_handler,没有的话抛出bad_handler异常,不能增加空间,结束返回0
            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)  //内部调用new_handler函数,如果不能增加空间:则,只要不成功就抛异常
                {       // 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 */

不同的编译器在动态内存分配上的实现细节不同,malloc函数在内存申请失败时返回NULL值,new关键字在内存申请失败时,可能返回NULL值,可能抛出bad_alloc异常。

猜你喜欢

转载自blog.csdn.net/ws857707645/article/details/80303328