new/delete用法

来源:互联网 发布:新浪微博数据统计工具 编辑:程序博客网 时间:2024/05/23 10:35

C++提供了new/delete操作符对内存进行动态定理,在使用有两种方式:C++运行库的默认全局方式和自定义实现。

一、C++运行库中的new/delete使用:

1.1、C++标准中关于new/delete的声明

namespace std

{

class bad_alloc;

struct nothrow_t {};

extern const nothrow_t  nothrow;

typedef void (*new_handler)();

new_handler set_new_handler(new_handler new_p) throw; // 通常用来自己处理内存分配失败异常

}

void * operator new(std::size_t size) throw(std::bad_alloc); // 分配失败,抛出异常

void * operator new(std::size_t size, const std::nothrow_t &) throw(); // 分配失败,返回0

void * operator delete(void *ptr) throw();

void * operator delete(void *ptr, const std::nothrow_t &) throw();

void * operator new[] (std::size_t size) throw(std::bad_alloc); // 分配失败,抛出异常

void * operator new[] (std::size_t size, const std::nothrow_t &) throw(); // 分配失败,返回0

void * operator delete[](void *ptr) throw();

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

void * operator new(std::size_t size, void *ptr) throw();     // placement new 返回指定位置的内存作为分配的内存

void * operator new[] (std::size_t size, void *ptr) throw();  // placement new 返回指定位置的内存作为分配的内存

void * operator delete(void *ptr, void*) throw();

void * operator delete[] (void *ptr, void*) throw();


1.2、自定义异常处理函数

一般情况下程序员并不对new/delete错误进行处理,而只是交给系统处理,系统调用通过set_new_handler函数设置的默认new_handler函数指针所指向的系统函数,另外还可以由程序员自定义异常处理函数来替换系统函数。Win32系统允许一个进程访问的空间达到4G,其中高2G为系统使用,低2G程序自己使用,下面我们设计一个程序:首先先分配100MB空间,然后进行20次循环,每次分配100MB,执行第19次会失败,此时会调用自己的异常处理函数,释放第一次100MB空间,然后成功申请,第20次时则不会再成功了。

#include <stdio.h>

#include <new>

char *gP = NULL;

void my_new_handler(void)

{

if(gP!=NULL)

{

printf("尝试获取更多的内存......\n");

delete[] gP;

gP = NULL;

}

else

{

printf("不能分配更多的内存......");

throw bad_alloc();

}

return;

}

int main()

{

set_new_handler(my_new_handler); // 安装自定义的异常处理函数

gP = new char[100*1024*1024]; // 首先分配100MB空间

        if(gP != NULL)

{

printf("分配的100MB内存地址起始于:0X%x.\n", gP);

}

char *p = NULL;

for(int i=0; i<20; i++)

{

p = new char[100*1024*1024];

                printf("%d * 100MB, p = 0X%x\n", i+1, p);

}

printf("完成.\n");

return 0;

}


1.3、关于placement new的用法

下面举个关于placement new的用法:

#include <stdio.h>

#include <new>

int main()

{

char buf[1024];

char *p = new (buffer) char[1024];

printf("buf:\t 0X%x \np:\t0X%x\n", buf, p);

return 0;

}

运行上面程序,可以发现打印出的地址是相同的,说明p获取的内存不是在堆中分配的,而是栈上的内存,所以用过后不用释放,上面语句类似于:

char buf[1024];

char *p = buf;

所不同的是,用new可以分配固定大小的空间给特定的指针使用,这种placement new适用于大量快速建立和销毁小对象的应用。


二、自定义new/delete使用:

2.1、扩展的placement new用法

随着C++标准的发展,上述operator new中可以加上附加参数,仍可归为placement new,这属于自定义重载使用。如下在Debug版下添加自己的处理。

#include <stdio.h>

#include <new>

using namespace std;

void *operator new(size_t n, char* file, int line)

{

printf("size: %d\nnew at %s, %d\n", n, file, line);

printf("now is here: %s", __func__);

return ::operator new(n);

}

void operator delete(void *p, char *file, int line)

{

printf("delete at %s, %d\n", file, line);

printf("now is here: %s", __func__);

::operator delete(p);

return;

}

// __FILE__表示这句所在的源文件名称

// __LINE__表示这句在源文件中的行数,还可以用#line 来指定行数值

// __func__表示该句所在的函数名称

#define new new(__FILE__, __LINE__)

int main()

{

char *p = new char[1024];

operator delete(p, __LINE__);

return;

}


2.2、自定义全局operator new/delete用法 

#include <stdio.h>

#include <new>

#include <stdlib.h>

using namespace std;


char *gP = NULL;

void my_new_handler(void)

{

if(gP!=NULL)

{

printf("尝试获取更多的内存......\n");

delete[] gP;

gP = NULL;

}

else

{

printf("不能分配更多的内存......");

throw bad_alloc();

}

return;

}

void *operator new(size_t size)

{

void *p = NULL;

printf("自定义operator new \n");

if(0==size)

return NULL;

while(1)

{

p = malloc(size);

                if(p!=NULL)

{

printf("分配成功!\n");

return p;

}

new_hadler gH = set_new_handler(0); // 御载当前内存分配异常函数并返回当前内存分配函数

set_new_handler(gH);

if(gH)

{

printf("调用 new_handler...\n");

(*gH)();

}

else

{

printf("没有内存可分配,也没有new_handler\n");

throw bad_alloc();

}

}

}

void operator delete(void *p)

{

printf("自定义operator delete\n");

return free(p);

}


int main()

{

set_new_handler(my_new_handler); // 安装自定义的异常处理函数

gP = new char[100*1024*1024]; // 首先分配100MB空间

        if(gP != NULL)

{

printf("分配的100MB内存地址起始于:0X%x.\n", gP);

}

char *p = NULL;

for(int i=0; i<20; i++)

{

p = new char[100*1024*1024];

                printf("%d * 100MB, p = 0X%x\n", i+1, p);

}

printf("完成.\n");

return 0;

}


2.3、自定义类成员函数的operator new/delete用法

operator new/delete可以定义在类体内,此时要作为static成员函数来处理,给所有的类对象使用。

#include <stdio.h>

#include <new>

using namespace std;

class A

{

private:

int m_nVal;

public:

static void * operator new(size_t size);

static void * operator new(size_t size, char *file, int line);

};

void *A::operator new(size_t size, char *file, int line)

{

printf("size: %d\nnew at %s, %d\n", n, file, line);

return ::operator new(size);

}

// new 后面是类名,size则为该类分配的内存空间大小

void *A::operator new(size_t size)

{

printf("size: %d\n", size);

return ::operator new(n);

}


class B: public A

{

private:

int m_nVal;

};

int main()

{

A *pA = new A(); // new的第一个参数是A类的大小

B *pB = new(__FILE__, __LINE__) B(); // new的第一个参数是B类的大小,这是placement new的用法

char *buf = new char[1024]; // 将调用运行库中的operator new

}


派生类对象B所使用的operator new/delete都是继承自A类的,可以通过判断分配空间的大小来对B类作特别处理,或是B类自定义自己的operator new/delete覆盖A类。

if( size != sizeof(A))

return ::operator new(size);   // 让B类调用运行库中的operator new



0 0
原创粉丝点击