new/delete工作机制:
使用new表达式时发生的三个步骤:
1、调用名为operator new的标准库函数,分配足够大的原始的未类型化的内存,以保存指定类型的一个对象
2、运行该类型的一个构造函数去初始化对象
3、返回指向新分配并构造的构造函数对象的指针
使用delete表达式时,发生的步骤:
1、调用对象的析构函数
2、 调用名为operator delete的标准库函数释放该对象所用的内存
Student * pstu = new Student;
new表达式:
a. opeartor new库函数 --> 专门用来开辟空间
b. 调用构造函数 --> 进行初始化
c. 返回所创建对象的首地址
delete表达式:
a. 调用析构函数
b. 调用operator delete库函数 --> 释放申请的空间
|
operator new/delete
operator new 和operator delete函数有两个重载版本
void * operator new (size_t);
void * operator new[](size_t);
|
void operator delete(void *);
void operator delete[](void *);
|
只能生成栈对象
不能通过new表达式来生成对象
1、将构造函数放入private区域
2、operator new函数 放入到private区域
private:
void * operator new(size_t count);
void operator delete(void * p);
//重写new/delete,可以不去实现,类外就不能调用new来创建对象
|
//只生产栈对象,不生成堆对象
//1.将构造函数放入private区域; new生成堆对象的第二步就是要调用构造函数,设置为私有,new就不能成功
//2.operator new函数 放入到private区域
#include<iostream>
#include<string.h>
#include<stdlib.h>
using namespace std;
class Student
{
private:
int _id;
char *_name;
void * operator new(size_t count){} //只是为了不生成堆对象,没必要重写
void operator delete(void *p){}
public:
Student(int id,const char *name):_id(id)
{
cout<<"Student()"<<endl;
_name = new char[strlen(name)+1];
strcpy(_name,name);
}
~Student()
{
cout<<"~Student()"<<endl;
delete []_name;
_name = NULL;
}
void print()const
{
cout<<"id:"<<_id<<endl;
cout<<"name:"<<_name<<endl;
}
};
|
int main(void)
{
//Student *stu = new Student(110,"meihao"); //new 创建Student类对象时才会调用Student类内部重写的new、delete表达式
Student stu1(110,"meihao");
stu1.print();
return 0;
}
|
只能生成堆对象
在创建栈对象时,不能调用构造函数或者析构函数
1、将构造函数放到private区域 //不可以
2、将析构函数放到private区域 //对于堆对象而言,执行 delete 表达式不能调用析构函数,表一不通过;public 声明 destory() 函数来进行资源释放
//只创建堆对象
//将析构函数放到private区域
#include<iostream>
#include<string.h>
#include<stdlib.h>
using namespace std;
class Student
{
private:
int _id;
char *_name;
public:
Student(int id,const char *name):_id(id)
{
cout<<"Student()"<<endl;
_name = new char[strlen(name)+1];
strcpy(_name,name);
}
private:
~Student()
{
cout<<"~Student()"<<endl;
delete []_name;
_name = NULL;
}
public:
void destory()
{
cout<<"destory()"<<endl;
delete this; //只能创建堆对象,对象调用会传递this指针
//this->~Student(); //这个也可以
}
void print()const
{
cout<<"id:"<<_id<<endl;
cout<<"name:"<<_name<<endl;
}
};
|
int main(void)
{
Student *stu1 = new Student(110,"meihao");
stu1->print();
//delete stu1; //不能调析构函数,无法释放
stu1->destory();
//Student stu1(110,"meihao"); //析构函数是私有,可以创建对象但是不能释放,编译不通过
return 0;
}
|
delete 和 delete[] 区别
///
/// @file testDelete[].cpp
/// @author meihao1203(meihao19931203@outlook.com)
/// @date 2018-08-11 19:47:35
///
#include<iostream>
using namespace std;
class A
{
public:
A():_a(new char[1])
{
++cnt;
cout<<"A()"<<endl;
}
~A()
{
delete []_a;
cout<<"~A()"<<cnt<<endl;
}
private:
static int cnt;
char* _a;
};
int A::cnt = 0;
int main()
{
int* arr = new int[2];
int* arr2 = new int[2];
delete arr;
delete []arr2; //内置类型都能正常释放
cout<<"------"<<endl;
A* arr3 = new A[2];
delete []arr3;
cout<<"------"<<endl;
A* arr4 = new A[2]; //只会调动一次析构函数
delete arr4;
return 0;
}
------
A()
A()
~A()2
~A()1
------
A()
A()
~A()2
//core dump
|
使用valgrind查看内存泄露:
内置类型,内存大小已经确定,系统可以记忆并且进行管理,在析构时不会调用析构函数。
类类型,delete ptr只用来释放ptr指向的内存。
delete []ptr用来指向ptr指向的内存,并逐一调用数组中每个对象的析构函数
|