new 运算符
创建并且初始化具有动态存储期的对象。
Explanation
new所做的工作:
- 分配内存空间
- 在分配的内存空间里,构造和初始化一个没有名字的对象,或者一个没有名字的对象数组。new表达式返回的是一个右值指针,指针指向的是分配空间的其实地址。
对于创建数组类型,所有的维度(除了第一个维度)必须是正的,类型std::size_t 的converted constant expression表达式。对于第一个维度,只要是能转换为类型std::size_t的表达式即可。这是唯一的一种,创建动态数组的方法。
int n = 42;
double a[n][5]; // error
auto p1 = new double[n][5]; // okay
auto p2 = new double[5][n]; // error
如果第一个维度的值不合规矩,比如是负数,则会在运行时,allocate之前,抛出异常。
Allocation
new表达书分配内存通过调用恰当的allocation函数,如果类型不是数组类型,调用的allocation函数是:operator new 函数;如果类型是数组类型,调用的函数,是operator new[] 函数。
c++会提供两种allocation 函数,global and class-specified functions。如果调用::new T,会调用global allocation 函数;如果调用new T,会先从class T中查找allocation 函数。
当调用allocation 函数的时候,程序会传入需要分配的内存空间。对于非数组对象,传入的数值为std::sizeof(T)。
对于数组,传入的数值就不确定了,对于很多实现,分配的空间需要包含数组包含的对象的数目,以方便之后,delete[]确定需要调用多少次析构函数。
new T; // calls operator new(sizeof(T))
new T[5]; // calls operator new[](sizeof(T)*5 + overhead)
new(2,f) T; // calls operator new(sizeof(T), 2, f)
Construction
分配好内存空间之后,将会调用构造函数。如果构造函数抛出异常,则会调用deallocation函数释放空间。
内存泄漏
内存泄漏通常出现在以下几种情况:
-
new的pointer 被重新赋值:
int* p = new int(7); // dynamically allocated int with value 7 p = nullptr; // memory leak
-
pointer离开作用域:
void f() { int* p = new int(7); } // memory leak
-
exception存在:
void f() { int* p = new int(7); g(); // may throw delete p; // okay if no exception } // memory leak if g() throws