C++ 中变量内存的分配分为堆栈(栈)和堆。
堆栈(栈):
在堆栈上分配的内存由程序自行进行管理,当变量超出作用域,标志着变量的生命周期结束,此时程序回收分配的内存。堆栈的生长方式是向上生长。
堆:
堆上的内存由程序员自行管理,分配内存的方式可以是C语言的malloc函数,也可以是C++语言中的new操作符。相对于堆栈,堆中分配的内存需要在变量生命周期结束的地方,由程序员手动回收分配的内存,回收方式可以是C语言的free函数,也可以是C++语言中的delete操作符。堆的生成方向是向下生长。
new,delete和malloc,free的区别:
1. new和delete是C++语言中的操作符,可以被重载;malloc,free是C语言中的函数。
2. new和delete除了可以处理C语言的内建类型,还可以处理C++语言的用户自定义类型;malloc, free是按字节进行处理。
3. new和delete对于用户自定义类型在分配变量内存之后,回收变量内存之前会分别调用自定义类型的构造函数和析构函数; malloc,free只负责分配和回收指定大小内存,不负责对象的构造和析构。
4. new和delete可以被重载。
在C++中操作符new和delete分别有6种原型:
前四种负责分配内存:
void* operator new(size_t size);
void* operator new[](size_t size);
void* operator new(size_t size, const nothrow_t&) noexcept; //带有nothorw,不抛出异常
void* operator new[](size_t size, const nothrow_t&) noexcept;
下面两种new被成为placement new不分配内存,负责在已分配的内存中构造对象:
void* operator new(size_t size, void* p) noexcept;
void* operator new[](size_t size, void* p) noexcept;
这两个特别的new操作可以在内存池中不需要释放内存的情况下重用内存。
对应的delete也有6种形式:
void operator delete(void* ptr) noexcept;
void operator delete[](void* ptr) noexcept;
void operator delete(void* ptr, const nothrow_t&) noexcept;
void operator delete[](void* ptr, const nothrow_t&) noexcept;
void operator delete(void* p, void*) noexcept;
void operator delete[](void* p, void*) noexcept;
实际中delete只有前两种方式有效。
delete中没有实现抛出异常的机制,所以delete的nothrow版本是多余(未定义),只是为了对应于new的版本进行调用。
delete中的placement版本同样是多余的,因为在delete中不存在内存的分配。
只有当new中,对象的构造函数产生异常时才掉用delete的后四个对应版本,其中placement版本的delete执行的是空操作。
重载operator new 和 operator delete 可以自定义内存的分配和释放,但是不能自定义构造函数和析构函数的调用。也就是构造函数和析构函数的调用是固定的。
#include <iostream>
using namespace std;
class Solution{
public:
void* operator new(size_t size)
{
void* ptr = ::operator new(size);
cout <<"new :"<< ptr << endl;
return ptr;
}
void* operator new[](size_t size)
{
void* ptr = ::operator new[](size);
cout << "new[] :" << ptr << endl;
return ptr;
}
void* operator new(size_t size, const nothrow_t&) /*noexcept*/
{
void* ptr = ::operator new(size, nothrow);
cout << "new nothrow :"<< ptr << endl;
return ptr;
}
void* operator new[](size_t size, const nothrow_t&) /*noexcept*/
{
void* ptr = ::operator new[](size, nothrow);
cout << "new[] nothrow :" << ptr << endl;
return ptr;
}
void* operator new(size_t size, void* p) /*noexcept*/
{
void* ptr = ::operator new(size, p);
cout << "placement new :" << ptr << endl;
return ptr;
}
void* operator new[](size_t size, void* p)/*noexcept*/
{
void* ptr = ::operator new(size, p);
cout << "placemen new[] :" << ptr << endl;
return ptr;
}
void operator delete(void* ptr) /*noexcept*/
{
cout << "delete :" << ptr << endl;
::operator delete(ptr);
}
void operator delete[](void* ptr) /*noexcept*/
{
cout << "delete[] :" << ptr << endl;
::operator delete[](ptr);
}
void operator delete(void* ptr, const nothrow_t&) /*noexcept*/
{
cout << "delete nothrow :" << ptr << endl;
::operator delete(ptr, nothrow);
}
void operator delete[](void* ptr, const nothrow_t&) /*noexcept*/
{
cout << "delete[] nothrow :" << ptr << endl;
::operator delete[](ptr, nothrow);
}
void operator delete(void* ptr, void* p) /*noexcept*/
{
cout << "placement delete :" << ptr << endl;
::operator delete(ptr, p);
}
void operator delete[](void* ptr, void* p) /*noexcept*/
{
cout << "placement delete[] :" << ptr << endl;
::operator delete[](ptr, p);
}
};
int main()
{
Solution* ptr = new Solution();
delete ptr;
Solution* ptr_a = new Solution[5];
delete[] ptr_a;
Solution* ptr1 = new (nothrow) Solution();
delete ptr1;
Solution* ptr1_a = new (nothrow) Solution[5];
delete[] ptr1_a;
Solution* ptr2 = new Solution();
Solution* ptr3 = new(ptr2) Solution();
delete ptr3;
Solution* ptr_a1 = new Solution[5];
Solution* ptr_a2 = new(ptr_a1) Solution[5];
delete[] ptr_a2;
return 0;
}
输出结果: