new、::operator new与placement new的区别

发布时间 2023-09-30 19:20:45作者: Jyang~

在内存管理中,::operator new()/::operator delete() 、delete/new、 placement new 是不同的:

::operator new():只是进行空间的申请而不调用构造函数,可以理解为只是对 malloc 的简单封装,返回 void* 。可以进行类内重载或者全局重载,类内没有重载则寻找全局new。

::operator delete():类似,只是对空间进行释放,而不调用析构函数,可以理解为是对 free 的简单封装。可以类内重载或者全局重载,类内没有重载则寻找全局delete。

new:分为三个步骤:

  1. 调用 ::operator new(sizeof(type)) 申请空间(首先查找类内的 ::operator new() )
  2. 调用 type->constructor 对申请的对象进行构造
  3. 返回对应的指针类型 type*

delete:同new,分为三个步骤:

  1. 调用对应的 type->destroy 进行析构(首先查找类内的 ::operator new() )
  2. 调用 ::operator delete(type*) 进行空间释放
  3. return
//类内重载new、delete
#include<string>
class test {
public:
	
	void* operator new(size_t n) {
		std::cout << "分配了" << n << "bytes" << std::endl;
		return malloc(n);
	}

	void operator delete(void* ptr) {
		std::cout << "释放内存" << std::endl;
		free(ptr);
	}

	test() {
		std::cout << "constructor" << std::endl;
	}
	void sayHello() {
		std::cout << text << std::endl;
	}

	~test() {
		std::cout << "destroy" << std::endl;
	}
private:
	std::string text = "hello world";
};

template<class T1,class T2>
void constructor(T1* ptr, const T2& value) {
	new(ptr)T1(value);
}

int main() {
	test* t2 = new test();
	delete t2;
}
//全局重载new、delete
void* operator new(size_t n) {
	std::cout << "分配" << n << "个bytes" << std::endl;
	return malloc(n);
}

void operator delete(void* p) {
	free(p);
}

#include<string>
class test {
public:
	test() {
		std::cout << "constructor" << std::endl;
	}
	void sayHello() {
		std::cout << text << std::endl;
	}

	~test() {
		std::cout << "destroy" << std::endl;
	}
private:
	std::string text = "hello world";
};

int main() {
	test* t1 = (test*)::operator new(sizeof(test));
	//t1->sayHello();//未初始化,打印失败
	t1->test::test();
	t1->sayHello();
	t1->~test();
	::operator delete(t1);
}

placement new:布局new,比较特殊的一种new,用于在已分配的内存上创建对象,不申请另外的空间,但是需要手动调用析构函数。在内存池中就可以看到对于 placement new 的使用了。

使用placement new的例子:

#include<string>
class test {
public:
	test() {
		std::cout << "constructor" << std::endl;
	}
	void sayHello() {
		std::cout << text << std::endl;
	}

	~test() {
		std::cout << "destroy" << std::endl;
	}
private:
	std::string text = "hello world";
};

template<class T1,class T2>
void constructor(T1* ptr, const T2& value) {
	new(ptr)T1(value);
}

int main() {
	char* buf = (char*)::operator new(sizeof(test) * 2);
	std::cout << (void*)buf << std::endl;	//打印buf地址
	//((test*)buf)->sayHello();//未初始化buf,打印出现问题
	constructor((test*)buf, test());
	std::cout << (void*)buf << std::endl;	//再次打印buf地址,没有改变
	((test*)buf)->sayHello();//已初始化,打印hello world
	((test*)buf)->~test();//手动析构对象
	delete buf;
}

小小总结:

真正申请和释放内存空间其实是在 ::operator new(size_t) 中调用 malloc() 和在 ::operator delete() 中调用 **free() **,构造函数和析构函数并不会申请或释放内存空间。而placement new不调用malloc,而是在已分配的内存上创建对象。