C++学习笔记(五)——使用new/delete创建栈/堆对象
创建栈对象,类中必须要由构造函数与析构函数(系统默认给的也可以),创建堆对象,除了类中必须要由构造函数与析构函数(系统默认给的也可以)外,还有一个条件就是new/delete可用。不论是只能创建栈对象还是只能创建堆对象,都必须要理解new/delete的工作机理才可以。
new/delete的工作机理
使用new表达式时发生的三个步骤:
- 调用名为operator new的标准库函数,分配足够大的原始的未类型化的内存,以保存指定类型的一个对象;
- 运行该类型的一个构造函数去初始化对象;
- 返回指向新分配并构造的构造函数对象的指针
使用delete表达式时,发生的步骤: - 调用对象的析构函数;
- 调用名为operator delete的标准库函数释放该对象所用的内存
切记:在类外使用new/delete时,new/delete调用构造/析构函数的方式是类外调用,即private内的构造/析构函数new/delete无法调用;在类内使用new/delete时,new/delete调用构造/析构函数的方式是类内调用,即private内的构造/析构函数new/delete可以调用。
只能创建栈对象,不能创建堆对象
依据上面的介绍,要实现这个功能就必须:== 使类外不得调用new/delete==。只有这样才不会产生堆对象。实现代码如下(代码5-1)
///
/// @file Student.cc
/// @date 2019-02-09 21:38:35
///
#include <string.h>
#include <stdlib.h>
#include <iostream>
using std::cout;
using std::endl;
//要求:只能生成栈对象
class Student
{
public:
Student(int id, const char * name)
:_id(id)
,_name(new char[strlen(name)+1])
{
strcpy(_name, name);
cout << "Student " << endl;
}
void print() const
{
cout << "id: " << _id << endl;
cout << "name : " << _name << endl;
}
~Student()
{
cout << "~Student()" << endl;
}
private:
void * operator new(size_t size);
//将new/delete放在private区重载,就不会创建堆对象了,但是还可以
//在类内用new/delete使用堆空间。
void operator delete(void * ret);
int _id;
char * _name;
};
int main()
{
// Student * ps1 = new Student(100,"Mike");
Student ps2(110,"Lili");
// ps1->print();
// delete ps1; //ps1是堆对象不会自动调用析构函数,必须手动删除
ps2.print();
return 0;
}
只能创建堆对象,不能创建栈对象
创建栈对象只需要构造/析构函数;创建堆对象时,需要调用new/delete,然后new/delete又会调用构造/析构函数。所以实现这个功能有两种方法:
- 将构造函数放入private,然后重载new函数:这个的实现目前存在难点即:当调用new时,先要执行operator new然后返回一个指针,之后再以类外调用的形式来调用构造函数。当构造函数是private时,new就没有办法调用构造函数了。就算类内设计了一个调用构造函数的函数,也没有办法调用该函数,因为对象都还没有创建出来,怎么来调用来对象内的函数呢?!,所以该方法目前没有办法实现。
- 将析构函数放入private,然后重载delete函数;
将析构函数放入private,然后重载delete函数
///
/// @file heapStudent.cc
/// @date 2019-02-09 21:38:35
///
#include <string.h>
#include <stdlib.h>
#include <iostream>
using std::cout;
using std::endl;
//栈对象的建立依赖于构造和析构函数的存在
//堆对象的建立依赖于new/delete的存在
//new/delete的实现以来与构造与析构函数的存在
class Student
{
public:
Student(int id, const char * name)
:_id(id)
,_name(new char[strlen(name) + 1]())
{
strcpy(_name, name);
cout << "Student " << endl;
}
void print() const
{
cout << "id: " << _id << endl;
cout << "name : " << _name << endl;
}
void destroy()
{
delete this;
}
void * operator new(size_t size)
{
cout << "new " << endl;
void * ret = malloc(size);
return ret;
}
void operator delete(void * ret)
{
cout << "delete " << endl;
free(ret);
}
private:
~Student()
{
delete( _name);
cout << "~Student()" << endl;
//delete this;//这样写会造成死循环:delete this->~Student -> delete this
}
int _id;
char * _name;
};
int main()
{
// Student ps(99,"Jack"); //创建失败
Student * ps1 = new Student(100,"Mike");
ps1->print();
ps1->destroy();//在destroy内调用delete这是就可以访问private区内的析构函数了
// delete ps1; //ps1是堆对象不会自动调用析构函数,必须手动删除
return 0;
}