C++ new new[]详解

精髓:
operator new()完成的操作一般只是分配内存;而构造函数的调用(如果需要)是在new运算符中完成的。
operator new和new 运算符是不同的,operator new只分配内存,而只要new出现无论是不是operator new都会调用new运算符从而调用析构函数。

例子是:

#ifndef __PLACEMENT_NEW_INLINE  

#define __PLACEMENT_NEW_INLINE  

inline void *__cdecl operator new(size_t, void *_P)  

        {return (_P); }  

#if     _MSC_VER >= 1200  

inline void __cdecl operator delete(void *, void *)  

    {return; }  

#endif

#endif

 

 

这是new.h下的源代码,可见这个placement new(一种operator new)只是简单的返回了地址而已,并没有调用构造函数,这就说明,构造函数是只要出现new就必定会调用的事实。
我们可以使用如下技术来在制定的内存上调用构造:
  1. A* s = new(p) A(XXX);
注意:这个new是placement new不分配内存,仅仅只call new运算符调用构造函数。

详解:

A* a = new A;

 我们知道这里分为两步:1.分配内存,2.调用A()构造对象.
事实上,分配内存这一操作就是由operator new(size_t)来完成的,如果类A重载了operator new,那么将调用A::operator new(size_t ),如果没有重载,就调用::operator new(size_t ),全局new操作符由C++默认提供。

 operator new的三种形式:

operator new有三种形式:
throwing (1)
void* operator new (std::size_t size) throw (std::bad_alloc);
nothrow (2)
void* operator new (std::size_t size, const std::nothrow_t& nothrow_value) throw();
placement (3)
void* operator new (std::size_t size, void* ptr) throw();
(1)(2)的区别仅是是否抛出异常,当分配失败时,前者会抛出bad_alloc异常,后者返回null,不会抛出异常。它们都分配一个固定大小的连续内存。
用法示例:
A* a = new A; //调用throwing(1)
A* a = new(std::nothrow) A; //调用nothrow(2)
(3)是placement new,它也是对operator new的一个重载,定义于<new>中,它多接收一个ptr参数,但它只是简单地返回ptr。
它可以实现在ptr所指地址上构建一个对象(通过调用其构造函数),这在内存池技术上有广泛应用。
new(p) A();// 这个操作实际上是先调用了 operator new,这个operator new就是placement new(注意placement new不会分配内存),然后在p处调用了构造函数
前面说到,new运算符都会调用operator new,而这里的operator new(size_t, void*)并没有什么作用,真正起作用的是new运算符的第二个步骤:在p处调用A构造函数。这里的p可以是动态分配的内存,也可以是栈中缓冲,如char buf[100]; new(buf) A();
placement new的主要作用只是将p放入ecx,并且调用其构造函数。

c++为什么定义了析构函数的类的operator new[]传入的参数会多4字节?
class A

{

public:

A()

{

std::cout<<"call A constructor"<<std::endl;

}

~A()

{

std::cout<<"call A destructor"<<std::endl;

}

void* operator new(size_t size)

{

std::cout<<"call A::operator new[] size:"<<size<<std::endl;

return malloc(size);

}

void operator delete[](void* p)

{

std::cout<<"call A::operator delete[]"<<std::endl;

free(p);

}

void operator delete(void* p)

{

free(p);

}

};

//cpp
#include
<iostream>
#include "A.h" void* operator new[](size_t size) { std::cout<<"call global new[] size: "<<size<<std::endl; return malloc(size); } void operator delete[](void* p) { std::cout<<"call global delete[] "<<std::endl; } int _tmain(int argc, _TCHAR* argv[]) { std::cout<<"sizeof A "<<sizeof(A)<<std::endl; A* p1 = new A[3]; delete []p1; system("pause"); return 0; }

 

 

注意:只要在类中重载了new[]运算,就可以使用new A[n]来动态new数组,并且按照自定义的new方式来分配内存。但是他不会去调用自定义的new因为这两个运算符没有关联。实现的时候应该像如下实现:
1 void * Time::operator new[](size_t size)//重载new[]()运算符,以分配数组
2 {
3 
4 std::cout<<"operator new[]() is called.Object size is "<<size<<std::endl;
5 
6 return malloc(size);//?//在自由存储中分配内存
7 
8 }

 

使用malloc连续分配数组需要的所有内存,而不是一个一个的来分配。即这个size等于一数组对象的所需要的内存量。
注意:如果所分配的对象显示定义了析构函数,那么size会比对象个数X对象占用内存4字节+对齐字节数,这里暂时不考虑字节对齐数,只考虑那四字节:
这四个字节是用来记录数组长度的,方便在delete的时候(这里不用在delete重载中显示写出来,因为delete包含了一种运算符属性,只要出现delete有析构,必定调用析构)对每一个对象调用一次析构。要确定对多大的内存块进行析构就是下面的算式决定:
  1. (size - 4)/(那多出来四字节的值)
很明显,那4字节的值等于调用析构函数的次数。
如果没有显示定义析构的话,就不会多那4字节,在删除那段申请出来的连续内存时,由于不用调用析构直接全部抹掉即可。
注意:不同的平台上编译器的实现都是不同的,所以是不是有那4字节都不一定。


下面是测试代码:
  1 #include<iostream>
  2 void* operator new[](size_t size)
  3 
  4 {
  5 
  6   std::cout<<"call global new[] size: "<<size<<std::endl;
  7 
  8   return malloc(size);
  9 
 10 }
 11 
 12 class Time
 13 
 14 {
 15 
 16 private:
 17 
 18   int hrs,mins,secs;//时,分,秒
 19 
 20 public:
 21 
 22   Time(int hrs=19,int mins=35,int secs=20);//默认参数的带参构造函数
 23 
 24   ~Time();//析构函数
 25 
 26   void showTime()const;
 27 
 28   Time operator ++();//重载前缀递增运算符,++x
 29 
 30   Time operator ++(int);//重载后缀递增运算法,x++
 31 
 32   bool operator ==(const Time &)const;//重载相等性运算符
 33 
 34   Time & operator =(const Time &);//重载赋值运算符
 35 
 36   void * operator new(size_t size);//重载new()运算符,如:int * pInt=new int(0);
 37 
 38   void operator delete(void * ptr);//重载delete()运算符,如:delete pInt;
 39 
 40   void * operator new[](size_t size);//重载new[]()运算符,以分配数组
 41 
 42   void operator delete[](void * ptr);//重载delete[]()运算符,以去配数组,释放数组所占内存
 43 
 44 };
 45 
 46 Time::Time(int hrs,int mins,int secs)
 47 
 48 {
 49 
 50   this->hrs=hrs;
 51 
 52   this->mins=mins;
 53 
 54   this->secs=secs;
 55 
 56   std::cout<<"Time类默认参数的带参构造函数 "<<(this->hrs)<<':'<<(this->mins)<<':'<<(this->secs)<<std::endl;
 57 
 58 }
 59 
 60  
 61 
 62 Time::~Time()
 63 
 64 {
 65 
 66   std::cout<<"Time类析构函数 "<<(this->hrs)<<':'<<(this->mins)<<':'<<(this->secs)<<std::endl;
 67 
 68 }
 69 
 70  
 71 
 72 void Time::showTime()const
 73 
 74 {
 75 
 76   std::cout<<"Time类showTime()const函数 "<<(this->hrs)<<':'<<(this->mins)<<':'<<(this->secs)<<std::endl;
 77 
 78 }
 79 
 80 Time Time::operator ++()//重载前缀递增运算符,++x
 81 
 82 {
 83 
 84   secs++;
 85 
 86   if(secs>=60)
 87 
 88   {
 89 
 90     secs=0;
 91 
 92     mins++;
 93 
 94     if(mins>=60)
 95 
 96     {
 97 
 98       mins=0;
 99 
100       hrs++;
101 
102       if(hrs>=24)
103 
104       {
105 
106         hrs=0;
107 
108       }
109 
110     }
111 
112   }
113 
114   return Time(hrs,mins,secs);//返回无名临时对象
115 
116 }
117 
118 Time Time::operator ++(int)//重载后缀递增运算法,x++
119 
120 {
121 
122   Time temp(hrs,mins,secs);//生成临时对象,并进行初始化
123 
124   ++secs;
125 
126   if(secs>=60)
127 
128   {
129 
130     secs=0;
131 
132     mins++;
133 
134     if(mins>=60)
135 
136     {
137 
138       mins=0;
139 
140       hrs++;
141 
142       if(hrs>=24)
143 
144       {
145 
146         hrs=0;
147 
148       }
149 
150     }
151 
152   }
153 
154   return temp;
155 
156 }
157 
158 bool Time::operator ==(const Time & aTime)const//重载相等性运算符
159 
160 {
161 
162   return ((hrs==aTime.hrs)&&(mins==aTime.mins)&&(secs==aTime.secs));
163 
164 }
165 
166 Time & Time::operator =(const Time & aTime)//重载赋值运算符
167 
168 {
169 
170   hrs=aTime.hrs;
171 
172   mins=aTime.mins;
173 
174   secs=aTime.secs;
175 
176   std::cout<<"Time类赋值运算符函数 "<<(this->hrs)<<':'<<(this->mins)<<':'<<(this->secs)<<std::endl;
177 
178   return (*this);//返回当前对象的引用
179 
180 }
181 
182 void * Time::operator new(size_t size)//重载new()运算符,如:int * pInt=new int();
183 
184 {
185 
186   std::cout<<"operator new() is called.Object size is "<<size<<std::endl;
187 
188   return malloc(size);//?//在自由存储中分配内存
189 
190 }
191 
192 void Time::operator delete(void * ptr)//重载delete()运算符,如:delete pInt;
193 
194 {
195 
196   std::cout<<"operator delete() is called"<<std::endl;
197 
198   free(ptr);//在自由存储中释放内存
199 
200 }
201 
202 void * Time::operator new[](size_t size)//重载new[]()运算符,以分配数组
203 
204 {
205 
206   std::cout<<"operator new[]() is called.Object size is "<<size<<std::endl;
207 
208   return malloc(size);//?//在自由存储中分配内存
209 
210 }
211 
212 void Time::operator delete[](void * ptr)//重载delete[]()运算符,以去配数组,释放数组所占内存
213 
214 {
215 
216   std::cout<<"operator delete[]() is called"<<std::endl;
217 
218   free(ptr);//在自由存储中释放内存
219 
220 }
221 
222  
223 
224 int main()
225 
226 {
227 
228   Time * pTime;
229 
230   pTime=new Time;//重载new()运算符,调用默认构造函数
231 
232   pTime->showTime();
233 
234   delete pTime;//重载delete()运算符
235 
236   pTime=new Time[3];//重载new[]()运算符,以分配数组,调用默认构造函数
237 
238   delete [] pTime;//重载delete[]()运算符,以去配数组,释放数组所占内存
239 
240   getchar();
241 
242   return 0;
243 
244 }

 

 

posted @ 2015-01-25 07:39  wubugui  阅读(7773)  评论(0编辑  收藏  举报