文章目录
第三章 new和delete表达式(堆对象)
〇、前提
栈对象在适当的时候自动生成,又在适当的时候自动销毁(只用构造函数、析构函数)
堆对象需要程序员自己申请空间、释放空间(需要operator new 构造函数、析构函数 operator delete )
一、new表达式工作步骤
使用new表达式时发生的三个步骤:
- 调用名为operator new的标准库函数,分配足够大的原始的未类型化的内存,以保存指定类型的一个对象
- 运行该类型的一个构造函数初始化对象
- 返回指向新分配并构造的构造函数对象的指针
二、delete表达式工作步骤
使用delete表达式时发生的两个步骤:
- 调用析构函数,回收对象中数据成员所申请的资源
- 调用名为operator delete的标准库函数释放该对象所用的内存
三、operator new和operator delete函数的重载版本
//operator new库函数
void * operator new(size_t);
void * operator new[](size_t);
//operator delete库函数
void operator delete(void *);
void operator delete[](void *);
例子:
class Student
{
public:
Student(int id, const char * name)
: _id(id)
, _name(new char[strlen(name) + 1]())
{
strcpy(_name, name);
cout << "Student()" << endl;
}
~Student()
{
if(_name)
{
delete [] _name;
_name = nullptr;
}
cout << "~Student()" << endl;
}
static void * operator new(size_t sz) //
{
//printf("this : %p\n",this); eroor,报错,不能使用this指针,所以是static函数
cout << "void *operator new(size_t)" << endl;
void * ret = malloc(sz);
return ret;
}
static void operator delete(void * pointer) //
{
cout << "void operator delete(void *)" << endl;
free(pointer);
}
void print() const
{
cout << "id:" << _id << endl
<< "name:" << _name << endl;
}
private:
int _id;
char *_name;
}
int main(void)
{
Student * stu = new Student(100, "Jackie");
stu->print();
//Q:对象的销毁与调用析构函数等价吗?
//A:不等价,对象的销毁会调用析构函数然后再free
delete stu;
return 0;
}
四、要求一个类只能创建栈对象
解决办法:将operator new,operator delete 放入Student类的private区域
栈对象的创建需要构造函数与析构函数都不能为private
如果要求一个类只能创建栈对象,其意思是在创建出栈对象的同时,不能创建堆对象。以Student类型而言:
//Q:栈对象在创建的时候需要哪些条件?
//A: 构造函数 和 析构函数 都不能为private (可以自己测试一下)
void test0()
{
Student s1(101, "John");//ok 栈对象
Student * stu = new Student(101, "Mark");//error 堆对象
}
//要达到以上的效果,需要将operator new,operator delete 放入Student类的private区域
五、要求一个类只能创建堆对象
解决办法:将析构函数设置为私有。
这样产生了一个问题:堆对象在类外无法delete。解决:堆对象delete时,在类内设置destory函数,类外调用destory函数从而delete堆对象。
如果要求一个类只能创建堆对象,其意思是在创建出堆对象的同时,不能创建栈对象。以Student类型而言:
void test1()
{
Student s1(101, "John");//error 栈对象
Student * stu = new Student(101, "Mark");//ok 堆对象
stu->detory();
}
//要达到以上的效果,需要将Student类的析构函数放入private区域
//而且需要在类里面封装为destory函数,堆对象通过调用destory进行delete this(释放对象本身)
class Student
{
public:
void destory()
{
// this->~Student();
delete this; //释放对象本身 delete的两个步骤:1.调用析构函数,2.调用operator delete
//析构函数是private,需要在类内才能调用析构函数
}
}
自己总结
Student s1(101, “John”);
栈对象的创建与销毁(构造函数与析构函数都不能为private)
构造函数
析构函数
Student * stu = new Student(100, “Jackie”);
delete stu;
堆对象的创建与销毁
new
- operator new
- 构造函数
- 分配
delete
- 析构函数
- operator delete
构造函数
析构函数
Student * stu = new Student(100, “Jackie”);
delete stu;
堆对象的创建与销毁
new
- operator new
- 构造函数
- 分配
delete
- 析构函数
- operator delete