有关php new deletee 的重载

当前访客身份:游客 [
这个人很懒,啥也没写
:java运行结果应该是 j=9 k=25 吧?
:public class UnsafeGuestbookServlet extends H...
:很详细,看得有些吃力了,
:很好啊,以前都不知道,收藏了。
:大开眼界,碉堡了
今日访问:0
昨日访问:8
本周访问:0
本月访问:36
所有访问:1803
转帖关于new/delete的运算符和malloc()/free()的标准库函数
发表于3年前( 10:54)&&
阅读(112)&|&评论()
0人收藏此文章,
new--------delete malloc--------free
我又一个对象类,里面有一个指针链表,动态分配空间,在析构的时候释放。开始对对象进行new操作,但是执行delete对象操作的时候出错,提示在析构的时候内存有问题。可是这时候成员一个比特的内存都没有分配啊。所以析构的时候应该什么内存操作都不执行。 更奇怪的是采用free()函数就可以释放这种对象,但是内存却不见减少,整个程序内存占用节节升高?这是为什么?
你在析构函数当中没有正确的释放你申请的内存,比如,这个对象当中有一个指针,是采用动态申请内存的,在构造函数当中应该把它的值设置为NULL,然后在某个方法当中会申请内存,是采用new方法进行申请的,在析构函当中,应该先判断该指针是否为空,如果不为空,则使用delete释放内存,然后再把该指针设置为NULL。这样就可以了,如果你在外面是采用new申请这个对象,则在使用完成后使用delete释放就可以了。
补充一点:new和malloc虽然都是申请内存,但申请的位置不同,new的内存从free store
分配,而malloc的内存从heap分配(详情请看ISO14882的内存管理部分),
free store和heap很相似,都是动态内存,但是位置不同,这就是为什么new
出来的内存不能通过free来释放的原因。不过微软编译器并没有很好的执行标准,
很有可能把free store和heap混淆了,因此,free有时也可以。再补充一点:delete时候不需要检查NULL
呵,我也来凑合 如果TYPE *p = new TYPE[n] 那么就要 delete[] p
malloc和free(及其变体)会产生问题的原因在于它们太简单:他们不知道构造函数和析构函数。
假设用两种方法给一个包含10个string对象的数组分配空间,一个用malloc,另一个用new:
string *stringarray1 = static_cast&string*&(malloc(10 * sizeof(string)));
string *stringarray2 = new string[10];
其结果是,stringarray1确实指向的是可以容纳10个string对象的足够空间,但内存里并没有创建这些对象。而且,如果你不从这种晦涩的语法怪圈(详见条款m4和m8的描述)里跳出来的话,你没有办法来初始化数组里的对象。换句话说,stringarray1其实一点用也没有。相反,stringarray2指向的是一个包含10个完全构造好的string对象的数组,每个对象可以在任何读取string的操作里安全使用。
假设你想了个怪招对stringarray1数组里的对象进行了初始化,那么在你后面的程序里你一定会这么做:
free(stringarray1); delete [] stringarray2;// 参见条款5:这里为什么要加上个&[]&
调用free将会释放stringarray1指向的内存,但内存里的string对象不会调用析构函数。如果string对象象一般情况那样,自己已经分配了内存,那这些内存将会全部丢失。相反,当对stringarray2调用delete时,数组里的每个对象都会在内存释放前调用析构函数。
既然new和delete可以这么有效地与构造函数和析构函数交互,选用它们是显然的。
把new和delete与malloc和free混在一起用也是个坏想法。对一个用new获取来的指针调用free,或者对一个用malloc获取来的指针调用delete,其后果是不可预测的。大家都知道“不可预测”的意思:它可能在开发阶段工作良好,在测试阶段工作良好,但也可能会最后在你最重要的客户的脸上爆炸。
new/delete和malloc/free的不兼容性常常会导致一些严重的复杂性问题。举个例子,&string.h&里通常有个strdup函数,它得到一个char*字符串然后返回其拷贝:
char * strdup(const char *ps); // 返回ps所指的拷贝 在有些地方,c和c++用的是同一个strdup版本,所以函数内部是用malloc分配内存。这样的话,一些不知情的c++程序员会在调用strdup后忽视了必须对strdup返回的指针进行free操作。为了防止这一情况,有些地方会专门为c++重写strdup,并在函数内部调用了new,这就要求其调用者记得最后用delete。你可以想象,这会导致多么严重的移植性问题,因为代码中strdup以不同的形式在不同的地方之间颠来倒去。
c++程序员和c程序员一样对代码重用十分感兴趣。大家都知道,有大量基于malloc和free写成的代码构成的c库都非常值得重用。在利用这些库时,最好是你不用负责去free掉由库自己malloc的内存,并且/或者,你不用去malloc库自己会free掉的内存,这样就太好了。其实,在c++程序里使用malloc和free没有错,只要保证用malloc得到的指针用free,或者用new得到的指针最后用delete来操作就可以了。千万别马虎地把new和free或malloc和delete混起来用,那只会自找麻烦。
既然malloc和free对构造函数和析构函数一无所知,把malloc/free和new/delete混起来用又象嘈杂拥挤的晚会那样难以控制,那么,你最好就什么时候都一心一意地使用new和delete吧。
malloc与free是C++/C语言的标准库函数,new/delete是C++的运算符。它们都可用于申请动态内存和释放内存。 对于非内部数据类型的对象而言,光用maloc/free无法满足动态对象的要求。对象在创建的同时要自动执行构造函数,对象在消亡之前要自动执行析构函数。由于malloc/free是库函数而不是运算符,不在编译器控制权限之内,不能够把执行构造函数和析构函数的任务强加于malloc/free。因此C++语言需要一个能完成动态内存分配和初始化工作的运算符new,以及一个能完成清理与释放内存工作的运算符delete。注意new/delete不是库函数。
delete的时候可能需要释放多个指针的内存 free和delete的区别是 对于对象来说 free的确释放了对象的内存,但是不调用对象的析构函数,所以如果在对象中使用new分配的内存就会泄露 delete不仅释放对象的内存,并且调用对象的析构函数
更多开发者职位上
1)">1)">1" ng-class="{current:{{currentPage==page}}}" ng-repeat="page in pages"><li class='page' ng-if="(endIndex<li class='page next' ng-if="(currentPage
相关文章阅读2295人阅读
最近做一个小项目,对c++又有很多新的理解。实在不的不让人发出感叹,c++太强大了,绝对不是一朝一夕就可以领悟她的内涵的。&&&&&&&首先我们要清楚,为什么我们要重载new,和delete了?这还不是指针造成的,确实指针是一件让人喜欢的东西,用起来如此让人喜欢,让人顺手。然而小程序我们完全可以避免内存泄露问题,大程序就不那么容易了,然而我们有一种特别好的方法可以跟踪我们new,和delete动作,找到未被释放的内存。办法是什么呢?微软给我们提供了一种很好的方法,那就是重载new,和delete。&&&&&&&在实现之前我们要清楚new,和delete的工作机理,这是个多么好的学习机会啊!&&&&&&&对与new操作符,其实和sizeof一样,都是c++内置的,然而像strlen就不是了,strlen属于函数。对于new的功能我们是没有办法改变的,当我们new一个对象时,new为我们做了两件事情,一、申请一块足够的内存空间供存放对象,对于new一个数组对象,编译器会计算出总共的空间,然后执行类似c语言中malloc函数类似的功能。二、初始化对象,对于单个对象,包括包括基本对象和类对象,可以通过括号初始化,比如int * pn = new int(3); A * pa = new A(3);&&&然而对于数组不能初始化,对于类对象,必须定义无参数的构造函数。对与new的基本功能我们是无法改变的。&&&&&&&我们所能改变的就是如何为对象分配内存,我们可一重载这个函数以实现分配内存。通常的重载方式是:&&&&&&&void * operator new (size_t size);&&&&&&&然而这已经足够了,在一般的operator new 重载函数里,我们可以再加入其它参数,但第一个参数必须是size_t类型,即为无符号整形。正是有这种特性,为我们对内存申请和释放的跟踪提供了可能。&&&&&&&具体实现就是第一个operator new 的重载函数,我们第一的这个函数是这样的:void * operator new(unsigned int size, const char *file, int line){&&&&cout && "new size:" && size &&&&&&cout && file && " " && line &&&&&&void * p = malloc(size);&&&&}&&&&&&&然后用宏替换所有的new:#define new new(__FILE__, __LINE__)&&&&&&&这样我们每次调用new,比如int * pn =被编译器替换成了int * pn = new (__FILE__, __LINE__) int,从而调用我们定义的operator new,这种办法确实很妙。需要交代的是,对于数组同样适用,而是在编译的是后由编译器计算出所需要的长度调用我们定义的operator new函数。&&&&&&&对于delete,我们无需使用宏定义,只要重载operator delete就可以了,然而我们需要重载两个delete:void operator delete(void * p){&&&&cout && "delete " && (int)p &&&&&&free(p);}void operator delete [] (void * p){&&&&cout && "delete [] " && (int)p &&&&&&free(p);}&&&&&&&其实后面一个函数的内容和前面的内容一样,但为了支持数组的释放,我们必须是要定义的。那么我们只是简单的free(p)编译器咋知道我们释放的数组,还是单个对象了,这个不用我们操心了,我们只要提供给free函数一个申请内存的首地址就可以了。因为在用malloc申请的时候,我们也把数组装换为内存大小了。&&&&&&&由此我们可以得出下面的推断:用int * pn = new int [100];的空间,用delete pn释放和delete [] pn释放效果一样。然而那么既然这两种方式一样,那还要delete [] 干什么,其实delete [] 有另外的作用就是类对象数组的释放,编译器把delete []解释为调用对象的析构函数,这个是通过循环实现的,最后释放掉申请的内存。&&&&&&&既然我们已经跟踪了new和delete,那么就可以比较容易的判断申请的内存是否最后得到释放,要完成它,我们还需要一个链表,或者其它,当我们申请一块内存的时候加入到链表中,释放一块空间的时候,从链表中删除和释放内存首地址相同的节点就可以了,最后理想的情况是链表为空,如果不为空,那就说明内存发生泄露(Memory leaks)了。完整代码:
#include "malloc.h"
#include "iostream.h"
#ifdef _DEBUG
void * operator new(unsigned int size, const char *file, int line)
cout && "new size:" && size &&
cout && file && " " && line &&
// 下面两种方法可以达到同样的效果,但下面一种比较好
// 因为用下面一种可以保持原有的申请方式一样
//void * p = malloc(size);
void * p = operator new(size);
void operator delete(void * p)
cout && "delete " && (int)p &&
void operator delete [] (void * p)
cout && "delete [] " && (int)p &&
void operator delete(void * p, const char *file, int line)
cout && "delete file line" &&
void operator delete [] (void * p, const char *file, int line)
cout && "delete [] file line" &&
#define new new(__FILE__, __LINE__)
void main()
int * p = new int[5];
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:19711次
排名:千里之外
转载:16篇
评论:11条
(2)(1)(1)(4)(9)(1)(3)重载全局new/delete实现内存检测 - CSDN博客
operator delete(pointer);
(delete [] (char*)(p));为什么可以重载全局的new 和delete 函数?
[问题点数:100分,结帖人afgkidy]
为什么可以重载全局的new 和delete 函数?
[问题点数:100分,结帖人afgkidy]
不显示删除回复
显示所有回复
显示星级回复
显示得分回复
只显示楼主
相关推荐:
2011年9月 C/C++大版内专家分月排行榜第二2011年4月 C/C++大版内专家分月排行榜第二2010年11月 C/C++大版内专家分月排行榜第二
2011年6月 C/C++大版内专家分月排行榜第三
2010年12月 C/C++大版内专家分月排行榜第二
2012年11月 挨踢职涯大版内专家分月排行榜第二2011年9月 Linux/Unix社区大版内专家分月排行榜第二
2012年1月 Linux/Unix社区大版内专家分月排行榜第三2011年8月 C/C++大版内专家分月排行榜第三2011年8月 Linux/Unix社区大版内专家分月排行榜第三2010年4月 C/C++大版内专家分月排行榜第三
2015年1月 C/C++大版内专家分月排行榜第二2012年3月 C/C++大版内专家分月排行榜第二2011年11月 C/C++大版内专家分月排行榜第二2010年6月 C/C++大版内专家分月排行榜第二2010年5月 C/C++大版内专家分月排行榜第二
2011年4月 C/C++大版内专家分月排行榜第三2011年2月 C/C++大版内专家分月排行榜第三2010年8月 C/C++大版内专家分月排行榜第三
2010年10月 C/C++大版内专家分月排行榜第二
2013年6月 Linux/Unix社区大版内专家分月排行榜第二2013年5月 Linux/Unix社区大版内专家分月排行榜第二2013年3月 Linux/Unix社区大版内专家分月排行榜第二2013年1月 Linux/Unix社区大版内专家分月排行榜第二2012年12月 Linux/Unix社区大版内专家分月排行榜第二2012年8月 Linux/Unix社区大版内专家分月排行榜第二2011年12月 Linux/Unix社区大版内专家分月排行榜第二2011年10月 C/C++大版内专家分月排行榜第二2011年10月 Linux/Unix社区大版内专家分月排行榜第二
2012年6月 C/C++大版内专家分月排行榜第三2012年6月 PHP大版内专家分月排行榜第三2012年5月 C/C++大版内专家分月排行榜第三2012年3月 Linux/Unix社区大版内专家分月排行榜第三2012年2月 Linux/Unix社区大版内专家分月排行榜第三2011年11月 C/C++大版内专家分月排行榜第三
2015年1月 C/C++大版内专家分月排行榜第二2012年3月 C/C++大版内专家分月排行榜第二2011年11月 C/C++大版内专家分月排行榜第二2010年6月 C/C++大版内专家分月排行榜第二2010年5月 C/C++大版内专家分月排行榜第二
2011年4月 C/C++大版内专家分月排行榜第三2011年2月 C/C++大版内专家分月排行榜第三2010年8月 C/C++大版内专家分月排行榜第三
本帖子已过去太久远了,不再提供回复功能。动态对象创建(二)重载new和delete-.Net-爱编程
动态对象创建(二)重载new和delete
动态对象创建(二)重载和
上文我简单介绍了一下动态对象创建的方法,这一篇文章的内容主要是对重载和做一些讲解,也希望能够得到博友们的指点,在这里谢过大家。
通常我们为了一些目的而使用和的内存分配系统,但是在特殊情况下,它并不能够满足需要。最常见的改变分配系统的原因是出于效率考虑:也许要创建和销毁一个特定的类的非常多的对象以至于这个运算变成了速度的瓶颈。允许重载和来实现我们自己的存储分配方案,所以可以用它来处理问题。
另一个问题就是堆碎片:分配不同大小的内存可能会在堆上产生很多碎片,以至于很快用完内存。虽然内存可能还有,但是由于都是碎片,也就找不到足够大的内存块满足需要。通过为特定类创建自己的内存分配器,可以确保这种情况不会发生。
当我们在重载和时,我们只是改变了原有的内存分配方法。编译器将用重载的代替默认版本去分配内存,然后为那个内存调用构造函数。所以,虽然当编译器看到时,编译器分配内存并调用构造函数,但是当重载时,可以改变的只是内存分配部分。
接下来,我分为三个部分详细讲解重载和:重载全局和、对于一个类重载和以及为数组重载和。
重载全局和
当我们重载全局的和的时候,可想而知,就会使默认版本完全不能被访问甚至在这个重新定义里也不能调用它们。
重载的必须有一个参数。这个参数由编译器产生并传递给我们,它是要分配内存的对象的长度。必须返回一个指向等于这个长度(或者大于这个长度)的对象的指针。如果没有找到存储单元(在这种情况下,构造函数不被调用),则返回一个。然后如果找不到存储单元,不能仅仅返回,我们还应该调用或产生一个异常信息之类的事,告诉这里出现了问题。
我们首先需要明白的一点就是:的返回值是一个,而不是指向任何特定类型的指针。所做的是分配内存,而不是完成一个对象建立直到构造函数调用了才完成对象的创建,它是编译器确保做的动作,不在我们的控制范围之内了,所以我们就没有必要考虑。
1 #include&iostream&
2 #include&cstdio&
3 #include&cstring&
4 #include&cstdlib&
5 #include&cmath&
6 #include&algorithm&
7 #define inf 0x7fffffff
8 using namespace
10 void* operator new(size_t sz)
printf("operator new: %d Bytes\n",sz);
void* m = malloc(sz);
if (!m) puts("out of memory");
18 void operator delete(void* m)
puts("operator delete");
24 class S
26 public:
S() {puts("S::S()"); }
~S() {puts("S::~S()"); }
29 private:
int an[1000];
33 int main()
puts("creating & destroying an int");
int* q = new int(23);
puts("creating & destroying an int[]");
int* p = new int[10]();
delete []p;
puts("creating & destroying an s");
S* s = new S;
puts("creating & destroying S[3]");
S* sa = new S[3];
对于一个类重载和
为一个类重载和的时候,尽管不必显式的使用,但是实际上仍是在创建成员函数。它的语法也和重载任何其它运算符一样。当编译器看到使用创建自己定义的类的对象时,它选择成员版本的而不是全局版本的。但是全局版本的和仍为所有其他类型对象使用(除非它们也有自己的和)。这个和全局变量、局部变量的意思是一样的,应该很好懂吧。
1 #include&iostream&
2 #include&cstddef&
3 #include&fstream&
4 #include&new&
5 using namespace
6 ofstream out("Framis.out");
8 class Framis
10 public:
enum{psize = 100 };
Framis() {out&& "Framis()" && }
~Framis() {out&& "~Framis() ... " && }
void* operator new(size_t) throw (bad_alloc);
void operator delete(void*);
16 private:
enum{sz = 10 };
char c[sz];
static unsigned char pool[];
static bool alloc_map[];
22 unsigned char Framis::pool[psize*sizeof(Framis)];
23 bool Framis::alloc_map[psize]={false};
25 void* Framis::operator new(size_t sz) throw(bad_alloc)
for (int i=0; i& ++i) {
if (!alloc_map[i]) {
out&& "using block " && i && " ... ";
alloc_map[i]=true;
return pool+(i*sizeof(Framis));
out&& "out of memory" &&
throw bad_alloc();
38 void Framis::operator delete(void* m)
if (!m) return;
unsigned long block = (unsigned long)m-(unsigned long)
block /= sizeof(Framis);
out&& "freeing block " && block &&
alloc_map[block]=false;
47 int main()
Framis* f[Framis::psize];
for (int i=0; i&Framis:: i++) {
f[i]=new F
} catch(bad_alloc) {
cerr&& "Out of memory!" &&
delete f[10];
Framis* X=new F
for (int j=0; j&Framis:: j++) {
delete f[j];
为数组重载和
上一段文字中我们讲到如果为一个类重载和,那么无论何时创建这个类的一个对象都将调用这些运算符。但是如果要创建这个类的一个对象数组的时候,全局就会被立即调用,用来为这个数组分配足够的内存。对此,我们可以通过为这个类重载运算符的数组版本,即和,来控制对象数组的内存分配。
1 #include&iostream&
2 #include&fstream&
3 #include&new&
4 using namespace
5 ofstream trace("ArrayOperatorNew.out");
7 class Widget
Widget() {trace&& "*" && }
~Widget() {trace&& "~" && }
void* operator new(size_t sz) {
trace&& "Widget::new: " && sz && " byte" &&
return ::new char[sz];
void operator delete(void* p) {
trace&& "Widget::delete" &&
::delete []p;
void* operator new[](size_t sz) {
trace&& "Widget::new[]: " && sz && " bytes" &&
return ::new char[sz];
void operator delete[](void* p) {
trace&& "Widget::delete[]" &&
::delete []p;
28 private:
enum{sz=10 };
int an[sz];
33 int main()
trace&& "new Widget" &&
Widget* w=new W
trace&&endl&& "delete Widget" &&
trace&&endl&& "new Widget[25]" &&
Widget* wa=new Widget[25];
trace&&endl&& "delete []Widget" &&
1:对于C++中的动态对象创建又有了新的认识,学习了重载new和delete
2:C++空类的大小是1
3:最让我激动的就是:C++程序把运行结果写入新创建的文档里面,这个和ACM里常用的文件读写还是不一样滴。
好吧,继续努力!!!
版权所有 爱编程 (C) Copyright 2012. . All Rights Reserved.
闽ICP备号-3
微信扫一扫关注爱编程,每天为您推送一篇经典技术文章。}

我要回帖

更多关于 php new delete 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信