c++之 new expression

news/2024/7/20 13:34:26 标签: c++, 内存管理, new expression

new 一个对象发生了什么?

1、new对象发生的事情

Complex *pc = new Complex(2,4);

当编译器看到上边代码时会做出以下动作:

Complex *pc;
try{
	void *mem = operator new(sizeof(Complex));//先分配内存空间
	pc = static_cast<Complex*>(mem);//指针转型
	pc->Complex::Complex(2,4)//在调用构造函数
}//
delete pc

编译器转为以下做法:

pc->~Complex()//先析构对象
operator delete(pc)//释放内存

看到编译器的操作,我们不仅想自己模仿一下编译器的操作:
我们可以这样做模拟操作系统的做法:

#include<iostream>
#include<string>
#include<memory>
using namespace std;
class A {
public:
	int id;
	A(int i) :id(i) {
		cout << "ctor.this=" << this << "id=" << id << endl;
	}
	~A() {
		cout << "dtor.this=" << this << endl;
	}
};
int main() {
	A* pA = new A(1);
	cout << pA->id << endl;
	pA->A::A(3);
	cout << pA->id << endl;
	pA->A::~A();
}

输出结果:
在这里插入图片描述

new 对象怎样发生的?

在这里插入图片描述

重载 ::operator new / :: operator delete(这个要小心使用)

#include<iostream>
#include<string>
#include<memory>
using namespace std;

void* myAlloc(size_t  size){//模仿全局的 
	return malloc(size);
} 

void myFree(void* ptr){
	return free(ptr);
}

inline void* operator new (size_t size){
	cout <<"全局的new() \n";
	return myAlloc(size);
}

inline void operator delete(void *ptr){
	cout <<"全局的delete() \n";
	return myFree(ptr);

} 

class Foo{
public:
	Foo(){
		cout << "ctor chenggong \n";
	}
	~Foo(){
		cout << "dtor chenggong \n";
	}
};

int main(){
	Foo *f = new Foo();
}

在这里插入图片描述

重载类中 operator new / operator new[] / operator delete /operatpr delete[]

array new,array delete

Foo *pc = new Foo[3];//唤醒三次默认构造函数,但是无法由参数赋值
delete[] pc //唤醒三次析构函数对于没有指针的成员也可以用 delete pc;具体原因如下图

在这里插入图片描述

#include<iostream>
#include<string>
#include<memory>
using namespace std;
class Foo{
public:
	int _id;
	Foo():_id(0){
		cout << "默认构造函数 this:"<< this <<"id = " << _id <<endl; 
	}
	Foo(int i):_id(i){
		cout << "构造函数 this:"<< this <<"id = " << _id <<endl; 
	}
	~Foo(){
		cout << "dtor.this"<< this << "id=" << _id << endl;
	}
	
};

int main(){
	cout <<" sizeof(Foo) ="<< sizeof(Foo) << endl;
	Foo *f = new Foo[3];
	Foo *tmp = f;
	cout << "buf=" << f << "tmp =" <<tmp << endl;
	for(int i=0;i<3;i++){
		new(tmp++)Foo(i);//调用有参数构造函数 
	}
	cout << "buf=" << f << "tmp=" <<tmp<<endl;
	delete[]f;
}

在这里插入图片描述

重载类中的operator new 和operator 可以方便我们管理管理内存
具体做法:

class Foo{
	public:
		static void *operator new(size_t size);
		static void operator delete(void* ptr,size_t size)
		static void *operator new[](size_t size);
		static void operator delete[](void* ptr,size_t size)
}

看例子:

#include<iostream>
#include<string>
#include<memory>
using namespace std;
class Foo{
public:
	int _id;
	long _data;
	string _str;
	Foo():_id(0){
		cout << "默认构造函数 this:"<< this <<"id = " << _id <<endl; 
	}
	Foo(int i):_id(i){
		cout << "构造函数 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* ptr,size_t size);
	static void* operator new[](size_t size);
	static void operator delete[](void *ptr,size_t size);
};


void* Foo::operator new(size_t size){
	Foo *p = (Foo*)malloc(size);
	cout<<"重载之后的new";
	return p; 
}

void Foo::operator delete(void* ptr,size_t size){
	cout<<"重载之后的delete";
	free(ptr); 
}
void* Foo::operator new[](size_t size){
	Foo *p = (Foo*)malloc(size);
	cout<<"重载之后的new[]";
	return p; 
}
void Foo::operator delete[](void* ptr,size_t size){
	cout<<"重载之后的delete[]";
	free(ptr); 
}


int main(){
	cout <<" sizeof(Foo) ="<< sizeof(Foo) << endl;
	Foo *f = new Foo(7);
	delete f;
	Foo *pArray = new Foo[7];
	delete[]pArray;
}

在这里插入图片描述

重载new()/delete()

我们可以重载class member operator(),可以写出很多版本,但是每一个版本都必须拥有独特的参数列,并且第一个参数必须是size_t.出现new(args…) 这就是placement new

我们可以重载delete() 并且写出很多版本,但他们绝不会被delete,只用当new所调用的构造函数抛出exception,才会调用这些重载的delete(),只可能这样调用,主要用来归还未能完全创建成功的对象所占用的内存
例子:

#include<iostream>
#include<string>
#include<memory>
#include<exception>
using namespace std;

class Bad{
};
class Foo{
	int _i;
public:

	Foo(){
		cout << "默认构造函数 this:"<< this <<endl; 
	}
	Foo(int i):_i(i){
		cout << "构造函数 this:"<< this  <<endl; 
		throw Bad();//抛出异常,测试delete(); 
	}
	
	//1、一般的operator new() 的重载 
	void* operator new(size_t size)
	{
		return malloc(size);
	}
	//2、这个是标准库已经提供的placement new() 的重载形式,模拟一下 
	void* operator new(size_t size,void *start)
	{
		return start;
	}
	//3、新的placement new 
	void* operator new(size_t size,long extra)
	{
		return malloc(size+extra);
	}
	//4、又一个新的placement new 
	void* operator new(size_t size,long extra,char init)
	{
		return malloc(size+extra);
	}
	//对用版本1的 
	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 << "operator delete(void*,long,char)" <<endl; 
	}
	
};

int main(){
	cout <<" Foo start ="<<endl;
	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);
}

在这里插入图片描述出现异常的时候没有调用operator delete(void*,long)


http://www.niftyadmin.cn/n/1712815.html

相关文章

Unity基础篇:解决Unity里OnTriggerStay2D失灵问题。

我们先来看一下OnTriggerStay2D的官方文档。 其大致意思为&#xff0c;对于进入Trigger里的物体&#xff0c;每帧都执行一次检测和逻辑代码。 我们来做一个小Demo。 意图使进入Trigger的物体生命值逐帧递减。 挂载上相应的脚本和组件。 NewBehaviourScript这样写 using Sys…

c++----右值引用

最近看了侯捷老师的书籍&#xff0c;看到了右值引用&#xff0c;梳理一下右值引用的用法&#xff0c;以及特点&#xff1a; 右值、左值 既然是右值引用&#xff0c;我们首先要理解的是什么是右值什么是左值&#xff1a; 1、位于赋值号&#xff08;&#xff09;左侧的表达式就…

Unity基础篇:Unity中的世界坐标和局部坐标,Transform和Translate等问题的讨论。

今天感触良多&#xff0c;故于此一记。 首先&#xff0c;对于世界坐标和局部坐标。 这是两个cube&#xff0c;是我们今天的主角。首先是这个父Cube&#xff0c;我们注意到它此时坐标为&#xff08;0,0,0&#xff09;&#xff0c;由于他在根目录&#xff0c;所以他的transform…

编程基础篇:Trie树解决字典问题。

小Hi和小Ho是一对好朋友&#xff0c;出生在信息化社会的他们对编程产生了莫大的兴趣&#xff0c;他们约定好互相帮助&#xff0c;在编程的学习道路上一同前进。 这一天&#xff0c;他们遇到了一本词典&#xff0c;于是小Hi就向小Ho提出了那个经典的问题&#xff1a;“小Ho&…

编程基础篇:#1082 : 然而沼跃鱼早就看穿了一切

fjxmlhx每天都在被沼跃鱼刷屏&#xff0c;因此他急切的找到了你希望你写一个程序屏蔽所有句子中的沼跃鱼(“marshtomp”&#xff0c;不区分大小写)。为了使句子不缺少成分&#xff0c;统一换成 “fjxmlhx” 。 输入 输入包括多行。 每行是一个字符串&#xff0c;长度不超过2…

哈工大操作系统实验lab1

实验内容 改写 bootsect.s 主要完成如下功能&#xff1a; bootsect.s 能在屏幕上打印一段提示信息“XXX is booting…”&#xff0c;其中 XXX 是你给自己的操作系统起的名字&#xff0c;例如 LZJos、Sunix 等&#xff08;可以上论坛上秀秀谁的 OS 名字最帅&#xff0c;也可以…

Java中基本数据类型的位数及存储最值

了解每个类型的占用字节数和能存储的最值&#xff0c;能够在编写程序时&#xff0c;较好的提供类型 一.八种基本的数据类型 二、Java四大数据类型分类 1、整型 byte 、short 、int 、long 2、浮点型 float 、 double 3、字符型 char 4、布尔型 boolean 三、分析基本数…

编程基础篇:#1039 : 字符消除

时间限制:1000ms 单点时限:1000ms 内存限制:256MB 描述 小Hi最近在玩一个字符消除游戏。给定一个只包含大写字母"ABC"的字符串s&#xff0c;消除过程是如下进行的&#xff1a; 1)如果s包含长度超过1的由相同字母组成的子串&#xff0c;那么这些子串会被同时消除&…