首页 > 代码库 > new delete 关键字深度解析

new delete 关键字深度解析

1、new调用了构造函数,delete调用了析构函数? 实际上这是一个错误的想法。

2、new确实是对malloc进行了包装,看不到源码,我们只能猜测一下,C++标准库中规定的operator new 操作有没有调用构造函数?我也还不知道。唯一正确就是"operator new typename(parameter) "实际上是分解为三个步骤:

看懂这句话就可以啦。operator new  /*参数1:*/ typename  ( /*"参数2 为:typename调用构造函数的参数,不是new 操作的“*/  parameter,...)

2.1)编译器根据我们提供参数1:typename,去计算字节长度,然后通过operator new(size_t sz,...)去申请内存。这过程中通过调用标准库malloc或相关函数向OS申请内存资源。(内存分配的细节属于操作系统领域,今天不深化)

2.2) 假设成功编译器生成在目标地址调用构造函数的代码,实际操作类似于placement new 操作:new(this) typename( parameter,...);这里才是调用构造函数的地方,调用构造函数不属于关键字new的行为,是编译器根据typename的解析出来的行为,增加在new分配内存地址之后的跟随操作。placement new称为原地构造操作,对应的方式调用析构函数,如果显示使用了这个构造式:new(this)Constructor(),则也要显式使用:this->Constructor()::~Constructor().(C++11)之后this为常量,所以要用其他指针来显式调用析构函数。

2.3)返回目标地址。(不探讨失败的情况,因为没看过编译器实现new的源码,所以无法正确猜想异常的情况,就不误人子弟)。

以上思想主要来自 Thinking in C++和百度到的链接博客,经过本人深化,从此不在担心new操作不适当使用了。

同理delete的操作则是:

编译器通过指针类型区调用目标类型的析构函数去析构对象,然后才执行类似free的行为,将内存区域会交给OS分配给程序的堆表中(OS和进程之间怎么关于内存管理这块我也不了解,希望了解-的朋友在评论中给我个链接,谢啦)。

这也是delete关键字处理void类型的指针可能出现内存泄露的原因。因为编译器无法推导该类型的内存区域大小,无法用某个格式化的方式去映射这片区域(实际上函数表中对应的析构函数都是void类型的)。编译器只能执行 free (void*)操作,向堆区提交单个void*长度地址,跟机器有关32位是4Bytes。除非delete的关键字的实现能访问OS的内存表,才能正确回收改块内存而不泄露。这也是C++标准委员会要解决内存回收机制的问题,实现难度实在太高了。

//仔细看delete参数即可知,delete关键字的操作是没有类型,不执行析构操作。

void * operator new(size_t count);
void operator delete(void *
p);

真正地重载new delete。很多种方式可供重载,同样new [] 数组 和 delete [] 数组也是很多种,少说有5种,目前没看过源码的api或标准库的说明资料。其他百度上面找得到的基本最后利用malloc和free去替换,而不是调用C++ 标准关键字 new/delelte去实现重载。


先看一小段:delete和delete[]的分析:

// TestNewDeleteArray.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <string>
#include <iostream>
#include <windows.h>

using namespace std;

class A
{
public:
	
	~A()
	{
		cout << "Goodbye A" << endl;
	}

	void * operator new[](size_t count)
	{
		cout << "size:" << count<<endl; //84
		return malloc(count);
	}

private:
	int i;
	int s;
};

void d(A*p)
{
	delete[] p;
}


int _tmain(int argc, _TCHAR* argv[])
{

	A* p;
	cout.setf(ios::hex);
	while (true)
	{
		p = new A[10];
		cout << p << endl; //011CC164,除了id一次不同之外
		delete p;
		p = NULL;
		Sleep(5000);
	}
	return 0;
}

1:delete 和 delete[]不能混用。

如图:


因为他们的内存分配方式不一致,new []分配的长度加上数组的结束符。也就是平时我与在string字符串中经常碰见的"\0"。实际上自定义类数据数组形式结束符长度为4字节(win32编译器)。待续。。


new delete 关键字深度解析