前言
个人学习笔记
一、new/delete表达式
1、new表达式工作步骤
1)先调用名为operator new的标准库函数,分配足够大的原始的未初始化的内存,用来保存指定类型的一个对象;
2)运行该类型的一个构造函数初始化对象;
3)返回指向新分配并构造的构造函数对象的指针;
2、delete表达式工作步骤
1)调用析构函数,回收对象中数据成员所申请的资源;
2)调用名为operator delete的标准库函数释放该对象所用的内存;
3、new/delete与operator new/operator delete区别
new是一个表达式也是一个关键字,operator new和operator delete整体是一个库函数,他们是new表达式里面的一个工作步骤。
//operator new库函数
void * operator new(size_t sz); //相当于C语言中的malloc,malloc返回的也是void *
void * operator new[](size_t sz);
//operator delete库函数
void operator delete(void * pret);
void operator delete[](void * pret);
二、operator new/operator delete的一般用法
当operator new/operator delete在类中作为成员函数的时候,没有this指针,编译器把他们当成静态成员函数;当operator new/operator delete作为全局函数的时候,只要使用了new/delete表达式,都会调用operator new/operator delete库函数。
对于栈对象而言,对象的销毁与析构函数的执行等价;而对于堆对象而言,对象的销毁与析构函数的执行是不等价的,对象的销毁除了要执行析构函数,还要执行operator delete,析构函数只是对象销毁的一部分。
代码如下(示例):
#include <string.h>
#include <iostream>
using std::cout;
using std::endl;
class Student
{
public:
Student(int age, const char *name)
:_age(age)
,_name(new char[strlen(name) + 1]())
{
strcpy(_name, name);
cout << "Student(int, const char *)" << endl;
}
static void * operator new(size_t sz)
{
/* printf("this = %p\n", this);//error 没有this指针 */
cout << "void *operator new(size_t)" << endl;
void * pret = malloc(sz);
return pret;
}
static void operator delete(void *pret)
{
/* printf("this = %p\n", this);//error 没有this指针 */
cout << "void operator delete(void *)" << endl;
free(pret);
}
~Student()
{
cout << "~Student()" << endl;
if(_name)
{
delete []_name;
_name = nullptr;
}
}
void print() const
{
cout << "_age = " << _age << endl;
cout << "_name = " << _name << endl;
}
private:
int _age;
char *_name;
};
int main()
{
Student *st = new Student(20, "wangwu");
st->print();
//对象的销毁与析构函数的执行等价吗?
//不等价,对于堆对象而言,析构函数的执行只是对象销毁的一个步骤
delete st;
return 0;
}
只能创建栈对象
如果要求一个类只能创建栈对象,那么意思就是说不能创建堆对象,而通过new创建堆对象有3个步骤,只要让其中一个不满足就可以,我们把operator new库函数设置为private,就可以达到目的了,为了与operator new库函数对应,所以这里把operator delete库函数也设置为private。由此可以看出栈对象创建的条件是:构造函数与析构函数都必须是public。
代码如下(示例):
#include <string.h>
#include <iostream>
using std::cout;
using std::endl;
class Student
{
public:
Student(int age, const char *name)
:_age(age)
,_name(new char[strlen(name) + 1]())
{
strcpy(_name, name);
cout << "Student(int, const char *)" << endl;
}
private:
static void * operator new(size_t sz)
{
/* printf("this = %p\n", this);//error 没有this指针 */
cout << "void *operator new(size_t)" << endl;
void * pret = malloc(sz);
return pret;
}
static void operator delete(void *pret)
{
/* printf("this = %p\n", this);//error 没有this指针 */
cout << "void operator delete(void *)" << endl;
free(pret);
}
public:
~Student()
{
cout << "~Student()" << endl;
if(_name)
{
delete []_name;
_name = nullptr;
}
}
void print() const
{
cout << "_age = " << _age << endl;
cout << "_name = " << _name << endl;
}
private:
int _age;
char *_name;
};
int main()
{
//问题:只能创建栈对象
//解决方案:将operator new/delete设置为私有的
//
//
//栈对象创建的条件是什么?
//构造函数和析构函数都必须设置为public
Student st1(18, "xiaoming");
/* Student *st = new Student(20, "wangwu"); //error */
/* st->print(); //error */
/* delete st; //error */
st1.print();
return 0;
}
只能创建堆对象
如果要求一个类只能创建堆对象,那就不能创建栈对象,而栈对象的创建条件是构造函数与析构函数都设置为public,堆对象在创建时需要使用public的构造函数,所以只能将析构函数设置为private,这样就不能创建栈对象了,此时为了销毁堆对象,所以需要设置一个过渡的函数来调用析构函数,因为析构函数比较特殊,不能直接在类中调用,这里我们可以通过this指针来调用析构函数,但是这样也有一个问题,因为堆对象的销毁不仅仅要调用析构函数释放数据成员申请占据的堆空间,还需要调用operator delete库函数来销毁类对象申请占据的堆空间,所以这里我们通过delete this指针的办法,因为this就代表对象本身,而delete需要的是对象的地址,这里刚好和this指针对应了,也就完美的解决了析构函数不能调用的问题,这里是this指针的2种特殊用法,这样就达到了只能创建堆对象,不能创建栈对象的目的。
代码如下(示例):
#include <string.h>
#include <iostream>
using std::cout;
using std::endl;
class Student
{
public:
Student(int age, const char *name)
:_age(age)
,_name(new char[strlen(name) + 1]())
{
strcpy(_name, name);
cout << "Student(int, const char *)" << endl;
}
static void * operator new(size_t sz)
{
cout << "void *operator new(size_t)" << endl;
void * pret = malloc(sz);
return pret;
}
static void operator delete(void *pret)
{
cout << "void operator delete(void *)" << endl;
free(pret);
}
private:
~Student()
{
cout << "~Student()" << endl;
if(_name)
{
delete []_name;
_name = nullptr;
}
}
public:
void print() const
{
cout << "_age = " << _age << endl;
cout << "_name = " << _name << endl;
}
void destroy()
{
//this指针的2种特殊用法
/* this->~Student(); */
delete this;//this指针指向对象本身
}
private:
int _age;
char *_name;
};
int main()
{
//问题:只能创建堆对象
//解决方案:将析构函数设置为私有,并且通过destroy函数delete this指针
/* Student st1(18, "xiaoming");//error */
/* st1.print();//error */
Student *st = new Student(20, "wangwu");//ok
st->print(); //ok
/* delete st; //error */
st->destroy();
return 0;
}