动态内存申请的结果——专题2

实验一:证明new_handler全局函数是否存在

#include <iostream>
#include <new>
#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)
    {
        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) 
    {
        cout << "operator new[]: " << size << endl;

        // return malloc(size);

        return NULL;
    }

    void operator delete[] (void* p)
    {
        cout << "operator delete[]: " << p << endl;

        free(p);
    }
};

//自定义new_handler函数
void my_new_handler()
{
    cout << "void my_new_handler()" << endl;
}

void ex_func_1()
{
    //在C++中new_handler是一个预定义的函数指针,指向的函数类型为没有返回值,没有参数的函数类型
    //set_new_handler将自定义的new_handler函数设置进去,当设置了自定义的函数之后,原来的new_handler函数将作为返回值返回。
    //注意,如果在编译器中没有默认的new_handler函数,那么执行完set_new_handler函数后将返回空。
    new_handler func = set_new_handler(my_new_handler);

    try
    {
        cout << "func = " << func << endl;

        if( func )
        {
            func();
        }
    }
    //这里想证明默认的处理函数new_handler确实抛出一个bad_alloc的异常。
    catch(const bad_alloc&)
    {
        cout << "catch(const bad_alloc&)" << endl;
    }
}


int main()
{
    ex_func_1();

    return 0;
}

Qt中的编译器打印结果:

func = 0;   说明在该编译器中没有默认的new_handler函数。

使用g++编译器,打印结果:

func = 0; 说明在该编译器中没有默认的new_handler函数

使用Visual studio 2010编译器,打印结果:

func = 00000000,说明在该编译器中没有默认的new_handler函数

使用bcc编译器,打印结果:
func = 某个地址

catch(const bad_alloc&) ,说明在该编译器中确实存在一个new_handler的全局函数。new_hander函数在调用之后,确实抛出了异常。

实验二:当动态申请失败时,统一编译器的行为,提供代码的移植性

#include <iostream>
#include <new>
#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) 
    {
        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) 
    {
        cout << "operator new[]: " << size << endl;

        // return malloc(size);

        return NULL;
    }

    void operator delete[] (void* p)
    {
        cout << "operator delete[]: " << p << endl;

        free(p);
    }
};

//自定义new_handler函数
void my_new_handler()
{
    cout << "void my_new_handler()" << endl;
}

void ex_func_2()
{
    Test* pt = new Test();
    cout << "pt = " << pt << endl;
    delete pt;
}

int main()
{
    ex_func_2();

    return 0;
}

利用g++编译器,运行结果如下:
operator new: 4
Test()
段错误

为什么会出现这种现象?

首先是调用了我们自己定义的new,然后分配内存失败,返回一个NULL,然后又在这个NULL上创建了一个对象,去操作0地址,不出现段错误才怪呢。

利用Qt编译器,结果如下:

operator new: 4
Test()

程序崩溃

Visual stdio 2010编译器,结果如下:

operator new: 4

pt = 0

从上面可以看出,3个编译器的行为是不统一的。为了提高程序的移植性,想要统一编译器的行为,又要怎么做呢?

想要统一编译器的行为为:不管哪个编译器,动态内存失败了,直接返回空指针就行了,不要做其他多余的事情了

对new的重载进行异常规格的说明,不管怎样都不会去扔出异常。

 void* operator new (unsigned int size) throw()
    {
        cout << "operator new: " << size << endl;

        // return malloc(size);

        return NULL;
    }


    void* operator new[] (unsigned int size) throw()
    {
        cout << "operator new[]: " << size << endl;

        // return malloc(size);

        return NULL;
    }

运行时结果:
operator new:4
pt = 0

实验三:在单次申请时告诉编译器不管结果是什么,都不要抛出异常。如果申请失败,直接返回空指针

#include <iostream>
#include <new>
#include <cstdlib>

using namespace std;

void ex_func_3()
{
    int* p = new(nothrow) int[10];
    cout << "pt = " << p << endl;
    delete[] p;

    int bb[2] = {0};
    struct ST
    {
        int x;
        int y;
    };
    //将ST对象创建到bb这个数组所在的栈空间。如何去做呢?
    //在指定的位置创建一个对象,通过new关键字来实现,后面的括号表明地址,即要将对象创建到哪的那个地址。
    ST* pt = new(bb) ST();

    pt->x = 1;
    pt->y = 2;

    //目的就是要看看,有没有将ST的对象创建到数组bb所在的内存空间上。
    cout << bb[0] << endl;
    cout << bb[1] << endl;

    //显示的调用析构函数,因为指定了创建对象的空间,此时必须要显式的手动的来调用析构函数了。
    pt->~ST();
}

int main()
{
    ex_func_3();

    return 0;
}

可以使用new关键字在指定的内存空间上创建对象,此时必须显式的调用构造函数

 

 

猜你喜欢

转载自www.cnblogs.com/-glb/p/12302363.html