New/Delect表达式
一、new表达式工作步骤
使用new表达式时发生的三个步骤:
- 调用名为operator new的标准库函数,分配足够大的原始的未初始化的内存,以保存指定类型的一个对象
- 运行该类型的一个构造函数初始化对象
- 返回指向新分配并构造的构造函数对象的指针
二、delete表达式工作步骤
使用delete表达式时发生的两个步骤:
- 调用析构函数,回收对象中数据成员所申请的资源
- 调用名为operator delete的标准库函数释放该对象所用的内存
#include <string.h>
#include <iostream>
#include <string>
#include <string.h>
using std::cout;
using std::endl;
using std::string;
//重载全局静态 ::operator new/delete,将导致其它类型new时使用重载过的
void * operator new(size_t sz)
{
/* printf("this : %p\n", this); //验证operator new是否含有this指针*/
cout << "全局静态void *operator new(size_t)" << endl;
void *ptr = malloc(sz);
return ptr;
}
void operator delete(void *ptr)
{
/* printf("this : %p\n", this); */
cout << "全局静态void operator delete (void *)" << endl;
free(ptr);
}
void * operator new[](size_t size){
void * ptr = malloc(size);
cout << "全局静态operator new[](size_t size)" << endl;
return ptr;
}
void operator delete[](void * ptr,size_t size){
cout << "全局静态operator delete[](void * ptr,size_t size)" << endl;
free(ptr);
}
class Foo{
public:
Foo():_id(0){
cout << "Foo() = " << this << " id = " << _id << endl;
}
Foo(int id,string name):_id(id),_name(name){
cout << "Foo(int id) = " << this << " id = " << _id << endl;
}
~Foo(){
cout << "~Foo() = " << this << " id = " << _id << endl;
}
void print() const
{
cout << "id: " << _id << endl
<< "name: " << _name << endl;
}
public:
//重载成员函数,静态,不含this指针
void * operator new(size_t size,int num);
void * operator new(size_t);
void operator delete(void *,size_t);//size_t可选
void operator delete(void * ptr,int num);
void * operator new[](size_t);
void operator delete[](void *,size_t);
private:
int _id;
long _data;
string _name;
};
void* Foo::operator new(size_t size){
/* printf("this : %p\n", this); //验证operator new是否含有this指针*/
Foo * ptr = (Foo *)malloc(size);
cout << "成员函数Foo::operator new(size_t size)" << endl;
return ptr;
}
void* Foo::operator new(size_t size,int num){
Foo * ptr = (Foo *)malloc(size);
cout << "重载后的成员函数Foo::operator new(size_t size,int num),num = " << num << endl;
return ptr;
}
void Foo::operator delete(void * ptr,size_t size){
cout << "成员函数Foo::operator delete(void * ptr,size_t size)" << endl;
free(ptr);
}
void Foo::operator delete(void * ptr,int num){
cout << "重载后的成员函数Foo::operator delete(void * ptr,int num)" << endl;
free(ptr);
}
void* Foo::operator new[](size_t size){
Foo * ptr = (Foo *)malloc(size);
cout << "成员函数Foo::operator new[](size_t size)" << endl;
return ptr;
}
void Foo::operator delete[](void * ptr,size_t size){
cout << "成员函数Foo::operator delete[](void * ptr,size_t size)" << endl;
free(ptr);
}
void test1(){
int N = 3;
Foo * p = new Foo(1,"hello");
//1 void * tmp = operator new(sizeof(Foo))
// p = static_cast<Foo*>(tmp);
//2 p->Foo::Foo();
//3 return p;
p->print();
delete p;
//1 p->Foo::~Foo();
//2 operator delect(p);
Foo * p1 = new Foo[N]();
cout << sizeof(Foo[N]) << endl;
//1 void * tmp = operator new(sizeof(Foo)*N + 4)
// p1 = static_cast<Foo*>(tmp);
//2 p1->Foo::Foo();//N次
//3 return p1;
delete []p1;
//1 p1->Foo::~Foo();//N次
//2 operator delect(p1);
//调用的是全局函数
Foo * p2 = ::new Foo();
::delete p2;
Foo * p3 = ::new Foo[N]();
::delete []p3;
}
void test2(){
//重载全局静态的new/delete,将导致其它类型new/delete时使用的是重载后的
string str = string("hello world");
char * tmp = new char[strlen(str.c_str()) + 1];
cout << str << endl;
delete []tmp;
}
void test3(){
//重载new/delete出多个版本,通过参数列表区分
Foo *p4 = new (1024)Foo();
delete p4;
}
int main(){
test1();
cout << endl << endl;
test2();
cout << endl << endl;
test3();
return 0;
}
- 重载的new/delete和全局的new/delete都为静态的,没有this指针
- 如果没有重载new/delete表达式,则使用的是全局静态的new/delete,重载了则使用重载的
- 在重载了new/delete表达式的情况下,可以显示的使用全局静态的new/delete
- 重载全局静态的new/delete,将导致其它类型new/delete时使用的是重载后的
- new[N]/delete[]一个对象,new出来的大小为sizeof(Foo) * N + sizeof(int),sizeof(int)是数组大小,不同的编译器可能不一致
- 可以重载new/delete出多个版本,但每一版的声明的参数列表都不相同,其中第一个参数必须为size_t,重载的出对应的delete只有在new所调用对象异常时,才会调用相应的delete回收未能完全创建对象的内存。
- 堆对象时,析构函数是对象销毁的一部分,而栈对象,析构函数直接销毁对象,没有operator delete
三、要求一个类只能创建栈对象
- 在创建出栈对象的同时,不能创建堆对象,operator new放入类的private区域
四、要求一个类只能创建堆对象
- 在创建出堆对象的同时,不能创栈堆对象,析构函数放入类的private区域
内存。
- 堆对象时,析构函数是对象销毁的一部分,而栈对象,析构函数直接销毁对象,没有operator delete
三、要求一个类只能创建栈对象
- 在创建出栈对象的同时,不能创建堆对象,operator new放入类的private区域
四、要求一个类只能创建堆对象
- 在创建出堆对象的同时,不能创栈堆对象,析构函数放入类的private区域