C++ operator new、operator delete、operator new []、operator delete []

operator new、operator delete

1、相关调用函数

1void* operator new(size_t size)
2void operator delete(void* p)
3void operator delete(void* p, size_t size)
4void* operator new [] (size_t size)
5void operator delete [] (void* p)
6void operator delete [] (void* p, size_t size)

2、new operator 和 operator new

定义

new operator: c++中的关键字new,无法重载,如A *a = new A;
operator new:c++中的一个操作符,用来服务于 new  操作符,可以被重载的,一般有全局默认的函数。 operator new [] 对应于new [] 相关的数组操作

举例:
A a = new A构造过程如下:*
分三步:

  1. 分配内存;
    分配内存这一操作就是由operator new(size_t)来完成的,如果类A重载了operator new,那么将调用A::operator new(size_t ),否则调用全局::operator new(size_t ),后者由C++默认提供。
  2. 调用A()构造对象;
    第二步在分配的内存上调用placement new(void * ptr) T(); “定位放置 new”,就是把对象构建在指定的ptr指向的内存上,换句话就是在指定的内存上调用构造函数。
  3. 返回分配指针
    最后一步就是返回新分配并构造好的对象的指针

调用函数

void* operator new (std::size_t size) throw (std::bad_alloc);
void* operator new (std::size_t size, const std::nothrow_t& nothrow_value) throw(); //nothrow new, 为了兼容以前的版本
void* operator new (std::size_t size, void* ptr) throw();

(1)(2)的区别仅是是否抛出异常,当分配失败时,前者会抛出bad_alloc异常,后者返回null,不会抛出异常。它们都分配一个固定大小的连续内存。

A* a = new A; //调用throwing(1)
A* a = new(std::nothrow) A; //调用nothrow(2)

3、delete operator 和 operator delete

delete operator :delete 操作符(关键字),无法重载
operator delete:用来服务于 delete 操作符,以及对应的  operator delete [] 对应于 delete []相关的数组操作;是可以被重载的,一般有全局默认的函数

举例:

class Foo{...}
Foo* pf = new Foo;
delete pf

(1)首先调用pf 指向对象的析构函数
(2)调用operator delete释放内存

4、new[] 和 delete[]

// https://blog.csdn.net/weixin_39411321/article/details/89310651
class Test
{
public:
    Test(){}
    ~Test(){}
private:
   int ma;
};

Test *p = new Test;   delete p;   		 //  =》  OK!
Test *p = new Test;   delete []p;  		//  =》  程序崩溃!
Test *p = new Test[10];   delete []p;   // =》  OK!
Test *p = new Test[10];   delete p;   	// =》 程序崩溃!

分析一下new和delete的具体操作是怎么进行的:
分析一下new和delete的具体操作是怎么进行的
在这里插入图片描述
但是当你去delete[]p;的时候,它是从哪里释放内存的?看看图:
在这里插入图片描述
为什么它会减四个字节开始释放内存呢?

因为定义了析构函数,在释放内存之前需要在内存中析构对象,你写个delete[]p,编译器就认为这里有很多对象要析构,多少个对象呢?记录对象个数的数字就在对象内存上面的4个字节存放,因此它从那里开始释放内存了,这肯定是要发生错误的!

总结:

  • 申请时在数组对象的上面还多分配了 4 个字节用来保存数组的大小,但是最终返回的是对象数组的指针,而不是所有分配空间的起始地址。
    调用析构函数的次数是从数组对象指针前面的 4 个字节中取出;
    传入 operator delete[] 函数的参数不是数组对象的指针
    ,而是 数组对象的指针 的值减 4。

5、运行实例(placement new用法)

#include<iostream>
using namespace std;
class Test
{
public:
	Test(int n) :n_(n)
	{
		cout << "Test(int n)..." << endl;
	}
	Test(const Test& other)
	{
		cout << "copy_Test......" << endl;
	}
	~Test() 
	{
		cout << "~Test()......" << endl;
	}
	int n_;
};

int main()
{
	char  chunk[10];//字符形式的,并不是整型形式显示出来的				
	//在chunk内存上new操作的,并没有分配新的内存
	//返回的p2指针,指向的还是上面chunk的地址(已经存在的地址),placement new用法
	//然后在调用构造函数,构造一个对象,放在chunk里面
	Test* p2 = new (chunk)Test(200);
	cout << p2->n_ << endl;//输出200

	cout << sizeof(*p2) << endl;//输出4 字节,这四个字节是chunk的四个字节

    //Test* p3 = (Test*)chunk;//验证:将chunk强制转化
	Test* p3 = reinterpret_cast<Test*>(chunk);
	cout << p3->n_ << endl;//输出200
	
	return 0;
}

在这里插入图片描述
在这里插入图片描述

6、new、delete的不同重载办法实例

#include<iostream>
using namespace std;
class Test
{
public:
	Test(int n) :n_(n)
	{
		cout << "Test(int n)..." << endl;
	}
	Test(const Test& other)
	{
		cout << "copy_Test......" << endl;
	}
	~Test() 
	{
		cout << "~Test()......" << endl;
	}

	void* operator new(size_t size)//new  operator 不能被重载
	{
		cout << "void* operator new ...." << endl;//验证operator new是不是被调用了
		void* p = malloc(size);
		return p;
	}
	void operator delete(void* p)
	{
		cout << "void operator delete......" << endl;//验证operator delete是不是被调用了
		free(p);
	}
	//可以和void operator delete(void* p)共存,不过优先调用前者
	void operator delete(void* p, size_t size)
	{
		cout << "void operator delete(void* p, size_t size) ......" << endl;//验证operator delete是不是被调用了
		free(p);
	}
	int n_;
};

void* operator new(size_t size)//new  operator 不能被重载
{
	cout << "global void* operator new ...." << endl;//验证operator new是不是被调用了
	void* p = malloc(size);
	return p;
}
void operator delete(void* p)
{
	cout << "global void operator delete......" << endl;//验证operator delete是不是被调用了
	free(p);
}

void* operator new[](size_t size)
{
	cout << "global void* operator new[] ...." << endl;//验证operator new[]是不是被调用了
	void* p = malloc(size);
	return p;
}
void operator delete[](void* p)
{
	cout << "global void operator delete[]......" << endl;//验证operator delete[]是不是被调用了
	free(p);
}


int main()
{
	//这里的new完成两个工作,
	//一个是new operator = operator new  +  构造函数的调用
	Test* p1 = new Test(100); 
	delete p1;

	char* str = new char;
	delete str;

	char* str1 = new char[10];
	delete[] str1;
	return 0;
}

在这里插入图片描述

参考

1、https://blog.csdn.net/sole_cc/article/details/84201248
2、https://www.cnblogs.com/cly-blog/p/5984660.html
3、https://blog.csdn.net/weixin_39411321/article/details/89310651
4、https://www.jianshu.com/p/d2d5cdd7aa1d

  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值