在記憶體管理中,::operator new()/::operator delete() 、delete/new、 placement new 是不同的: ::operator new():只是進行空間的申請而不調用構造函數,可以理解為只是對 malloc 的簡單封裝,返回 void* 。可以進行類內 ...
在記憶體管理中,::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,而是在已分配的記憶體上創建對象。