先看一下new和malloc的区别:
动态存储分配的运算符与函数的区别
malloc( )和free()是动态存储管理函数;
new 和delete是动态存储管理运算符。
它们功能类似但完全不同。
前者是函数,运行需要头文件,返回值无类型,创建对象时不调用构造函数(销毁对象时不调用析构函数);
而后者是运算符,不需要头文件,返回值有类型,创建对象时调用构造函数(销毁对象时调用析构函数)。
1.new 的三种使用方式
指针= new 类型名T 此时将调用无参构造函数;
指针= new 类型名T(初值列表) 此时将调用有参构造函数;
指针= new 类型名T [ size ] 此时将调用无参构造函数;
动态创建对象数组举例
#include<iostream>
using namespace std;
class Point
{
public:
Point()
{ X=Y=0; cout<<"Default Constructor called.\n";}
Point(int xx,int yy)
{ X=xx; Y=yy; cout<< "Constructor called.\n"; }
~Point() { cout<<"Destructor called.\n"; }
int GetX() {return X;}
int GetY() {return Y;}
void Move(int x,int y){ X=x; Y=y; }
private:
int X,Y;
};
void main()
{
Point *Ptr=new Point[2]; //创建对象数组
Ptr[0].Move(5,10); //通过指针访问数组元素的成员
Ptr[1].Move(15,20); //通过指针访问数组元素的成员
cout<<"Deleting..."<<endl;
delete[ ] Ptr; //删除整个对象数组
}
动态数组类
#include<iostream>
using namespace std;
class Point
{
public:
Point()
{ X=Y=0; cout<<"Default Constructor called.\n";}
Point(int xx,int yy)
{ X=xx; Y=yy; cout<< "Constructor called.\n"; }
~Point() { cout<<"Destructor called.\n"; }
int GetX() {return X;}
int GetY() {return Y;}
void Move(int x,int y){ X=x; Y=y; }
private:
int X,Y;
};
class ArrayOfPoints //这个类叫“控制类”
{
public:
ArrayOfPoints(int n) // 按照指示创建指定个数的对象
{
numberOfPoints = n;
points = new Point[n];
}
~ArrayOfPoints()
{
cout<<"Deleting..."<<endl;
numberOfPoints=0;
delete[] points;
}
Point& Element(int n)
{
return points[n];
}
private:
Point *points; //类内只保存对象数组的首址
int numberOfPoints; //对象的个数
};
void main()
{
int number;
cout<<"Please enter the number of points:";
cin>>number; //由用户指定对象个数
//创建ArrayOfPoints对象points,该对象聚集了//Point类的对象数组
ArrayOfPoints points(number);
//通过指针访问数组元素的成员(两个层次)
points.Element(0).Move(5,10);
cout<<"points.Element(0): "<<points.Element(0).GetX()<<","<<points.Element(0).GetY()<<endl;
//通过指针访问数组元素的成员
points.Element(1).Move(15,20);
cout<<"points.Element(1): "<<points.Element(1).GetX()<<","<<points.Element(1).GetY()<<endl;
}
输出结果:
Please enter the number of points:2
Default Constructor called.
Default Constructor called.
points.Element(0): 5,10
points.Element(1): 15,20
Deleting...
Destructor called.
Destructor called.
Press any key to continue
动态创建多维数组
指针= new 类型名T[下标表达式1][下标表达式2]…;
如果内存申请成功,new运算返回一个指向新分配内存首地址的指针,是一个T类型的数组。
数组元素的个数为除最左边一维外各维下标表达式的乘积。
例如:char (*fp)[3]; fp= new char[2][3];
fp应是个指向多维数组的指针,指针的类型应是char [3],这是“大元素”类型,其中内嵌了一维数组。所以*fp一定要加括号,所以一定比对象数组少一维。
创建动态对象数组的又几种形式
Point a[2]={Point(1,2),Point(3,4)};
这叫“创建对象数组”,尽管无名,但不在堆区,在栈区。
Point b[2]={*new Point(1,2),*new Point(3,4)};
这叫“动态创建对象数组”,在堆区。
Point *Ptr=new Point[2];
这叫“动态创建无名对象数组”,在堆区。
Point *c[2]={new Point(1,2), new Point(3,4)};
这叫“动态创建对象指针数组”,在堆区。
new 的种类
plain new 普通new
void*operator new(std::size_t)throw(std::bad_alloc);
void operator delete( void *) throw();
nothrownew 不抛掷异常new
void*operator new(std::size_t,conststd::nothrow_t
& )throw();
void operator delete( void *) throw();
placement new 放置new
void*operator new(std::size_t,void );
void operator delete( void * ,void );
1. 普通new 的用法
该运算符在分配失败时将抛出异常,而非返回NULL。使用时要包含<new>头文件。
char *getMemory(unsignedlong size)
{
char * p = newchar[size];
return p;
}
void main(void)
{
try{
char * p = getMemory(1000000);//可能发生异常
// ...
delete [ ] p;
}
catch(conststd::bad_alloc& ex)
{ cout<<ex.what(); }
}
2.不抛掷异常new 的用法
该运算符在分配失败时不抛出异常,而是返回NULL。使用时要包含<new>头文件。
该函数的第2形参是structnothrow_t{ };类的全局常对象const nothrow_tnothrow; 用来作为new 运算符的标志.
void func(unsingedlong length)
{ unsingedchar * p = new(nothrow)
unsingedchar[length];
if ( p == NULL)
cout<<“alloctefailed !”;
// ...
delete [ ] p;
}
3.放置new 的用法
该运算符是在已分配的内存上重新构造对象,因为不分配内存,所以不必担心分配失败。唯一的工作是调用构造函数。要包含<new>头文件。
# include <new>
# include<iostream>
void main()
{
using namespace std;
char * p = new(nothrow) char [4]; //用nothrow
if (p == NULL)
{ cout<<“alloctefailed”<<endl; exit( -1 ); }
long * q = new(p)long(1000); //用placement
delete [ ]p; //只释放p,不要释放q.
}
p和q仅仅是首址相同,所构建的对象可以类型不同。所“放置”的空间应小于原空间,以防不测。
该运算符的作用是:只要第一次分配成功,不再担心分配失败。
# include <new>
# include<iostream>
void main()
{ using namespace std;
char * p = new(nothrow) char [100]; //用nothrow
if (p == NULL)
{ cout<<“alloctefailed”<<endl; exit( -1 ); }
// ...
long * q1 = new(p)long(100); //用placement
// ...
long * q2 = new(p) int[100/sizeof(int) ];
// ...
ADT * q3 = new(p) C[100/sizeof(ADT) ];
delete [ ]p; //释放.
}
注意:使用该运算符一定要显式调用析构函数,不可用delete代替析构,因为placement new 的对象的大小不再与原空间相同。
# include <new>
# include<iostream>
void main()
{ using namespace std;
char * p = new(nothrow) char [sizeof(ADT)+2];
if (p == NULL)
{ cout<<“alloctefailed”<<endl; exit( -1 ); }
// ...
ADT * q = new(p) ADT;
// ...
// delete q; // 错误
q-> ADT::~ADT();
delete [ ]p; //再释放内存.
}