您的位置:首页 > 编程语言 > C语言/C++

c++ 内存申请

2015-12-24 17:58 435 查看
问题:

1:动态申请内存

如下:

int *d = new int【10】;

delete []d;

在用malloc()申请内存时,最好多申请一个单位的内存,不然会在free()时会出错,如下:

(摘自以以为网上大牛例子)

今天碰到到了free函数释放内存的错误,而且真的很难搞懂,上网一搜,竟然还有类似的,按照他的说法,修改自己的程序,还就通过了。看来以后用free函数之前,malloc函数有事没事,多分配一个空间是保险的。

下面是查到的内容:原文网址为:http://blog.csdn.net/lll10000/archive/2007/09/20/1792910.aspx



在VC 6.0 下编译的C程序,源代码如下:

#include <stdio.h>

#include <string.h>

#include <malloc.h>

int main()

{

char *s, *t;

char *r;

s = "Hello ";

t = "world!\n";

r = (char *)malloc(strlen(s) + strlen(t));

strcpy(r, s);

strcat(r, t);

printf(r);

free(r);

return 0;

}



  编译和连接都没有问题,但是在运行的时候出现:

Debug Error!

DAMAGE:after Normal block (#43) at 0x003707A8



  初步判断应该是在调用函数strcpy和strcat时,对r进行了修改,产生越界,从而释放内存失败。

检查以后果然发现在malloc(strlen(s) + strlen(t))时少分配了一个长度;(strlen函数去掉了字符串末尾的'/0'字符),导致在调用strcat的时候长度不够,因而重新动态分配了内存地址。

  将函数改为:

int main()

{

char *s, *t;

char *r;

s = "Hello ";

t = "world!\n";

r = (char *)malloc(strlen(s) + strlen(t) + 1);

strcpy(r, s);

strcat(r, t);

printf(r);

free(r);

return 0;

}

就不再报错了!

当写出p = new P();这样的代码的时候, 实际上有两步操作, 首先分配内存,然后在分配好的内存之上初始化类成员.

第二步是有构造函数完成的,
第一步就是new函数的工作.

全局的new有六种重载形式,

void *operator new(std::size_t count)

throw(std::bad_alloc); //一般的版本

void *operator new(std::size_t count, //兼容早版本的new

const
std::nothrow_t&) throw(); //内存分配失败不会抛出异常

void *operator new(std::size_t count, void *ptr) throw();

//placement版本

void *operator new[](std::size_t count) //

throw(std::bad_alloc);

void *operator new[](std::size_t count, //

const
std::nothrow_t&) throw();

void *operator new[](std::size_t count, void *ptr) throw();

所以, 刚才的用法, 就是使用new函数的一种重载形式.

如果A这个对象以同样实行重载了new函数的化, 作为成员函数

会被优先调用.

C++的各种new简介

1.new T

第一种new最简单,调用类的(如果重载了的话)或者全局的operator new分配空间,然后用

类型后面列的参数来调用构造函数,用法是

new TypeName(initial_args_list). 如果没有参数,括号一般可以省略.例如

int *p=new int;

int *p=new int(10);

int *p=new foo("hello");

通过调用delete来销毁:

delete p;

2. new T[]

这种new用来创建一个动态的对象数组,他会调用对象的operator new[]来分配内存(如果

没有则调用operator new,搜索顺序同上),然后调用对象的默认构造函数初始化每个对象

用法:

new TypeName[num_of_objects];

例如

int *p= new int[10];

销毁时使用operator delete[]

3.new()T 和new() T[]

这是个带参数的new,这种形式的new会调用operator new(size_t,OtherType)来分配内存

这里的OtherType要和new括号里的参数的类型兼容,

这种语法通常用来在某个特定的地址构件对象,称为placement new,前提是operator new

(size_t,void*)已经定义,通常编译器已经提供了一个实现,包含<new>头文件即可,这个

实现只是简单的把参数的指定的地址返回,因而new()运算符就会在括号里的地址上创建

对象

需要说明的是,第二个参数不是一定要是void*,可以识别的合法类型,这时候由C++的重载

机制来决定调用那个operator new

当然,我们可以提供自己的operator new(size_,Type),来决定new的行为,比如

char data[1000][sizeof(foo)];

inline void* operator new(size_t ,int n)

{

return
data
;

}

就可以使用这样有趣的语法来创建对象:

foo *p=new(6) foo(); //把对象创建在data的第六个单元上

的确很有意思

标准库还提供了一个nothrow的实现:

void* operator new(std::size_t, const std::nothrow_t&) throw();

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

就可以实现调用new失败时不抛出异常

new(nothrow) int(10);

// nothrow 是std::nothrow_t的一个实例

placement new 创建的对象不能直接delete来销毁,而是要调用对象的析够函数来销毁对

象,至于对象所占的内存如何处理,要看这块内存的具体来源

4. operator new(size_t)

这个的运算符分配参数指定大小的内存并返回首地址,可以为自定义的类重载这个运算符,

方法就是在类里面声明加上

void *operator new(size_t size)

{

//在这里分配内存并返回其地址

}

无论是否声明,类里面重载的各种operator new和operator delete都是具有static属性的

一般不需要直接调用operator new,除非直接分配原始内存(这一点类似于C的malloc)

在冲突的情况下要调用全局的operator加上::作用域运算符:

::operator new(1000); // 分配1000个字节

返回的内存需要回收的话,调用对应的operator delete

5.operator new[](size_t)

这个也是分配内存,,只不过是专门针对数组,也就是new T[]这种形式,当然,需要时可以

显式调用

6.operator new(size_t size, OtherType other_value)

和operator new[](size_t size, OtherType other_value)

参见上面的new()

需要强调的是,new用来创建对象并分配内存,它的行为是不可改变的,可以改变的是各种

operator new,我们就可以通过重载operator new来实现我们的内存分配方案.

1) new operator,也叫new表达式 ,就是我们惯常使用的new

      string* ps = new string("abc");

      上面这个new表达式完成了两件事情:申请内存和初始化对象

2) operator new,也叫new操作符。

plan new , nothrow new , placement new (不知将placement new 归为此类是否正确

1>> plan new



      new操作符类似于C语言中的malloc,只是负责申请内存,例如:

      void* buffer = operator new(sizeof(string));

      注意这里多了一个operator。

      在C++中是这样定义的:

       void* operator new(std::size_t) throw(std::bad_alloc);

       void operator delete(void *) throw();

      提示:plain new在分配失败的情况下,抛出异常std::bad_alloc而不是返回NULL,

因此通过判断返回值是否为NULL是徒劳的。 

     2>> nothrow new  是不抛出异常的运算符new的形式。

      nothrow new在失败时,返回NULL。定义如下:

       void * operator new(std::size_t,const std::nothrow_t&) throw();

       void operator delete(void*) throw(); 

        例:

         1. unsigned char *p = new(nothrow) unsigned char[length];

         2. if(p == NULL) cout<<"allocate failed!"<<endl;

        3. // ...

         4. delete []p;

3>> placement new 它用于在给定的内存中初始化对象

这种new允许在一块已经分配成功的内存上重新构造对象或对象数组。

不用担心内存分配失败,因为它根本不分配内存,它做的唯一一件事情就是调用对象的构造函数。

定义如下:

void* operator new(size_t,void*);

void operator delete(void*,void*);

placement new是在指定位置初始化对象,也就是调用了构造函数,因此与之对应的就是析构函数了,

      必须显示的调用类的析构函数释放对象。但此时内存空间仍然不会被释放,以供其他的对象使用。

      组后仍然要调用 delete 释放内存空间

    class A

    {

      public:

        A();

        ~A();

      private:

        int a ;

        int b;

    };

    void *pv = operator new(sizeof(A)) ;

    pv = new(pv) (sizeof(A)) ;

static_cast(A*)(pv)->~A();

    pv = NULL ;

主要应用场合:

1>> 的主要用途就是反复使用一块较大的动态分配的内存来构造不同类型的对象或者他们的数组。

2>> 构造起来的对象或其数组,要显示的调用他们的析构函数来销毁,千万不要使用delete。



与new对应的delete语法只有两种:

    1. delete operator delete表达式

      delete表达式和new表达式对应,完成对象的析构和内存的释放操作。

      string* ps = new string("abc");

      delete ps; //调用delete表达式,先析构再释放

    2. operator delete delete操作符。

      delete 操作符只是用于内存的释放,和C语言中的free相似。

      例如:

        void* buffer = operator new(sizeof(string));

        operator delete(buffer); //释放

    
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: