一、应用格式:
type_name * pointer_name = new type_name [num_elements];
delete [] pointer_name; //[]加不加取决于new有没有用[],两者必须对应。
tips:
1、delete仅仅释放指针指向的内存,而不删除指针本身。
2、注意覆盖与新建的区别,代码如下:
#include <iostream>
#include <cstring>
using namespace std;
int main()
{
char *p = new char[4];
strcpy(p, "asd");
cout << p << " at " << (int *)p << endl;
delete [] p; /*加这句,输出的地址一致,不加,输出的地址不一致*/
p = new char[4]; /*这个操作并不是覆盖,而是新建*/
strcpy(p, "qwe");
cout << p << " at " << (int *)p << endl;
delete [] p;
return 0;
}
二、定位运算符new:(new运算符的变体)
1、使用前应包含头文件new,#include <new>。
2、格式:pointer_name1 = new (pointer_name2) int[num] //在pointer_name2所指向的存储空间中开辟出int[num]个字节的空间,用于存储int数据,并把首位地址赋给pointer_name1。int也可以是其他类型。若分配的位置原来有其他值,则会被覆盖。
3、用定位运算符创建对象后,若要删除对象,不能用delete,因为delete只与常规new运算符对应,而不与定位运算符对应。所以必须显式的为定位运算符new创建的对象调用析构函数。代码如下:
char * fp = new char[40]; /*这里的char[4]仅仅表示1(char)*40个字节,不代表存入的数据一定为char*/
class_name *sp;
*sp = new (fp) class_name;
sp->~class_name(); /*显式调用析构函数*/
三、new/delete与动态数组:读取100个字符串并输出,各字符串长短不一,但均小于80.代码如下:
#include <iostream>
#include <cstring>
using namespace std;
char * getname(void);
int main()
{
char * name;
for(int i = 0; i < 100; i++){
name = getname();
cout << name << " at " << (int *) name << "\n";
/*这里可添加对name进行的操作,在用完name以后,调用delete对其进行内存释放,则内存可再次使用*/
delete [] name; /*delete本质上释放的是指针指向的内存块内容*/
}
return 0;
}
char * getname() /*这一块内容实现了动态内存分配*/
{
char temp[80]; /*temp在该代码块运行结束后会自动删除*/
cout << "Enter last name: ";
cin >> temp;
char * pn = new char[strlen(temp) + 1]; /*代码块运行结束后不会自动删除,需调用delete*/
strcpy(pn, temp);
return pn;
}
四、new/delete与类构造:
1、构造函数:应用new即可。
2、复制构造函数:应该自定义复制构造函数,不能使用默认的。因为默认的复制构造函数会导致不同对象的指针成员指向同一内存块,进而导致在调用析构函数的时候,对同一内存块使用两次delete,引发错误。
3、赋值运算符:应该使用自定义赋值运算符,原因同复制构造函数。正确代码如下:
/*类class_name中的成员包括指向字符串的指针pointer_name,int型的字符串长度值len*/
class_name & class_name::operator=(const class_name & cn)
{
if(this == &cn)
return *this; /*这一步用于检测=左右两边是不是同一对象,复制构造函数不需要这一步。*/
delete [] pointer_name; /*pointer_name为类中的指针成员*/
len = cn.len; /*获取cn中字符串长度*/
pointer_name = new char[len + 1] ;
strcpy(pointer_name,cn.pointer_name) ;
return *this;
}
4、析构函数:
添加delet [] pointer_name 即可。[]加不加看情况。若对象用new创建,则析构函数不会自动调用,除非显式使用delete删除对象,才会调用析构函数。
五、类继承中的new/delete
1、基类使用new,派生类不使用new,不需要做特殊的改进。
2、基类使用new,派生类使用new,易知需要为派生类重新设置与new匹配的析构函数,复制构造函数等。
a、析构函数,因为派生类析构函数会自动调用基类析构函数处理基类部分数据,所以派生类析构函
数只需要处理派生类中新增的数据部分即可。
b、复制构造函数,SA::SA(const SA & sa) : FA(sa) //必须像这样使用初始化列表调用基类复制构造函
数。
c、赋值运算符:在类方法实现中显式调用基类赋值运算符重载函数。代码如下:
SA & SA::operator=(const & sa)
{
if(this == &sa)
return *this;
FA::operator=(sa); /*显式调用基类赋值运算符重载函数*/
/*接下去就是派生类应有的赋值操作*/
return *this;
}