new、::operator new与placement new的区别
在内存管理中,::operator new()/::operator delete() 、delete/new、 placement new 是不同的:
::operator new():只是进行空间的申请而不调用构造函数,可以理解为只是对 malloc
的简单封装,返回 void*
。可以进行类内重载或者全局重载,类内没有重载则寻找全局new。
::operator delete():类似,只是对空间进行释放,而不调用析构函数,可以理解为是对 free
的简单封装。可以类内重载或者全局重载,类内没有重载则寻找全局delete。
new:分为三个步骤:
- 调用 ::operator new(sizeof(type)) 申请空间(首先查找类内的 ::operator new() )
- 调用 type->constructor 对申请的对象进行构造
- 返回对应的指针类型 type*
delete:同new,分为三个步骤:
- 调用对应的 type->destroy 进行析构(首先查找类内的 ::operator new() )
- 调用 ::operator delete(type*) 进行空间释放
- 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,而是在已分配的内存上创建对象。