Geekband C++面向对象高级程序设计-第五周课程3
#new与delete回顾
new:先分配memory内存,在调用ctor构造函数。
#转换方式
- Complex类
class Complex{
public:
Complex(int _m_real,int _m_imag):
m_real(_m_real),m_imag(_m_imag){ }
private:
double m_real;
double m_real;
};
- 创建类对象
Complex* pc=new Complex(1,2);
- 编译器转换
void* mem=operator new(sizeof(Complex)); pc=static_cast<Complex*>(mem); pc->Complex::Complex(1,2);
- 图模型

delete:先调用dtor,在释放memory
- 调用析构函数
delete pc;
- 编译器转换为
Complex::~Complex(pc); operator delete(pc);
- 图模型

- #补充:表达式行为不可改变,即不能重载也即 new 所分解出1,2,3 delete 所分解出1,2的事实不可改变。但是分解后的函数可以重载。
- #补充:析构函数并不释放内存,释放内存为独立操作。
#重载(全局)::operator new new[] 或者 重载::operator delete delete[]
- 全局函数
void* myAlloc(size_t size){
return malloc(size);
}
void myFree(void* ptr){
return free(ptr);
}
- 上述四个函数重载实例
inline void* operator new(size_t size){
cout << "global new() " <<endl;
return myAlloc(size);
}
inline void* operator new[](size_t size){
cout << "global new[]() " <<endl;
return myAlloc(size);
}
inline void operator delete(void* ptr){
cout << "global delete() " <<endl;
myFree(ptr);
}
inline void operator delete[](void* ptr){
cout << "global delete[]() " <<endl;
myFree(ptr);
}
- #补充:new需要一个参数,开辟内存空间的大小。delete需要传递指向需要销毁内存的指针,以便销毁内存。
#重载member operator new/delete
- #提示:对类中的成员做重载。
- Foo类
class Foo{
public:
void* operator new(size_t);
void operator delete(void*,size_t);
};
- 构造函数与析构函数调用
Foo* p = new Foo; delete p;
- 编译器转换方式
try{
void* mem = operator new(sizeof(Foo));
p = static_cast<Foo*>(mem);
p->Foo::Foo();
}
p->~Foo(); operator delete(p);
- 图模型
#重载member operator new[]/delete[]
#需要注意new与delete的语法规则,与重载函数的语法规则。同时注意内部函数写法。
- Foo类
class Foo{
public:
void* operator new[](size_t);
void operator delete[](void*,size_t);
};
- 构造函数析构函数调用
Foo* p = new Foo[N]; delete[] p;
- 编译器转换方式
try{
void* mem = operator new(sizeof(Foo)*n+4);
p->Foo::Foo();
}
p->~Foo();
operator delete(p);
- 图模型

#示例程序
- Foo类
class Foo{
public:
int _id;
long _data;
string _str;
public:
Foo():_id(0){
cout << "default ctor.this= " << this <<endl;
}
Foo(int i):_id(i){
cout << "ctor.this=" << this << "id=" <<_id <<endl;
}
~Foo(){
cout << "dtor.this=" << this << "id=" << _id <<endl;
}
static void* operator new(size_t size);
static void operator delete(void* pdead,size_t size);
static void* operator new[](size_t size);
static void operator delete[](void* pdead,size_t size);
};
- 类成员函数
void* Foo::operator new(size_t size){
Foo* p = (Foo*)malloc(size);
cout<<"new"<<endl;
return p;
}
void Foo::operator delete(void* pdead,size_t size){
cout << "delete" <<endl;
free(pdead);
}
void* Foo::operator new[](size_t size){
Foo* p = (Foo*)malloc(size);
cout << "new[]" <<endl;
return p;
}
void Foo::operator delete[](void* pdead,size_t size){
cout << "delete[]" <<endl;
free(pdead);
}
- 调用构造函数与析构函数
int main(){
Foo* pf = new Foo;
delete pf;
Foo* pf1 = ::new Foo;
::delete pf1;
return 0;
}
#补充:强制全局new与delete可用::new ::new[] ::delete ::delete[]。同样若没有全局函数大可不必这样写,其直接调用全局函数。
#内存结构探索
- 代码示例
#include <iostream>
#include <string>
using namespace std;
class Foo{
public:
int _id;
long _data;
string _str;
public:
Foo():_id(0){
cout << "ctor.this = " << this<<endl;
}
~Foo(){
cout << "dtor.this = " << this<<endl;
}
static void* operator new(size_t size);
static void operator delete(void* pdead,size_t size);
static void* operator new[](size_t size);
static void operator delete[](void* pdead,size_t size);
};
void* Foo::operator new(size_t size){
Foo* p = (Foo*)malloc(size);
cout <<"Foo::operator new() "<<"size ="<<size<<endl;
return p;
}
void Foo::operator delete(void* pdead,size_t size){
cout << "Foo::operator delete() "<<"size ="<<size<<endl;
free(pdead);
}
void* Foo::operator new[](size_t size){
Foo* p = (Foo*)malloc(size);
cout << "Foo::operator new[] "<<"size ="<<size<<endl;
return p;
}
void Foo::operator delete[](void* pdead,size_t size){
cout << "Foo::operator delete[] "<<"size ="<<size<<endl;
free(pdead);
}
int main(){
Foo* pf = new Foo;
delete pf;
Foo* pf1 = new Foo[5];
delete[] pf1;
// Foo* pf1 = ::new Foo;
// ::delete pf1;
return 0;
}
- 运行结果

#补充说明
由运行结果可以分析得出,构造函数的内存分配由上至下,析构函数的内存释放由下至上。并且,对于对象数组其内存会多分配8个字节,用来存放对象数组相关信息。
#重载new() delete()
class member operator new() 可以重载出多个版本,但是其必须符合重载要求每个声明都要有独特的参数列,其中第一个参数必须是size_t,其余参数以new所指定的placement arguments为初值。出现new()小括号内的记为placement arguments。
- 示例
Foo* pf = new(300,'c')Foo;
同时可以重载class member operator delete()但是并非必须。重载的delete被调用时当且仅当new所调用的ctor构造函数抛出异常exception。之所以被这样调用,主要是用来归还未能完全创建成功的对象object所占用的memory。
- 测试实例
#include <iostream>
using namespace std;
class Foo{
public:
Foo(){
cout<<"Foo::Foo()"<<endl;
}
Foo(int){
cout<<"Foo::Foo(int)"<<endl;
}
//operator new() 重载
void* operator new(size_t size){
return malloc(size);
}
//标准库提供placement new() 的重载
void* operator new(size_t size,void* start){
return start;
}
//新的placement new
void* operator new(size_t size,long extra){
return malloc(size+extra);
}
//新的placement new
void* operator new(size_t size,long extra,char init) {
return malloc(size+extra);
}
//故意写错
// void* operator new(long extra,char init){
// return malloc(extra);
// }
//一般operator delete()的重载
void operator delete(void*,size_t){
cout<<"operator delete(void*,size_t"<<endl;
}
//对应2
void operator delete(void*,void*){
cout<<"operator delete(void*,void*)"<<endl;
}
//对应3
void operator delete(void*,long){
cout << "operator delete(void*,long)"<<endl;
}
//对应4
void operator delete(void*,long,char){
cout<<"opertor delete(void*,long,char)"<<endl;
}
};
int main(){
Foo start;
Foo* p1 = new Foo;
Foo* p2 = new(&start)Foo;
Foo* p3 = new(100)Foo;
Foo* p4 = new(100,'a')Foo;
Foo* p5 = new(100)Foo(1);
Foo* p6 = new(100,'a')Foo(1);
Foo* p7 = new(&start)Foo(1);
Foo* p8 = new Foo(1);
return 0;
}
#补充:测试代码写错部分在dev C++ 中无法编译通过。侯捷老师在不同版本编译器中,编译通过后可运行跳转到自定义delete中,而另一款编译器编译通过后,并没有跳转自定义delete。
另外即使不写出一一对应的delete也不会有任何报错,编译器编译通过会报warning,显示出自动放弃检查警告。
#Basic_String
- basic_string 使用new(extra)扩充申请量
class basic_string{
private:
void release() {
if(--ref==0){
delete this;
}
}
inline static void* operator new(size_t,size_t);
inline static void operator delete(void*);
inline static Rep* create(size_t);
};
basic_string<charT,traits,Allocator>::Rep::
create(size_t extra){
extra = frob_size(extra+1);
Rep* p = new(extra)Rep;
return p;
}
template<class charT,class traits,class Allocator>
inline void* basic_string<charT,traits,Allocator>::Rep::
operator new(size_t,size_t extra){
return Allocator::allocate(s+extra*sizeof(charT));
}
#补充说明:此为侯捷老师添加标准库代码的例子,例子并不完整,摘抄其中一部分代码,new 调用时经过成员函数create的调用得到调用。

浙公网安备 33010602011771号