new 和 delete

常规变量存储在被称为 的内存区域中,而 new 从被称为 自由存储区 的内存区域中分配内存

new 分配的内存使用 delete 释放,已经释放的内存不能再用 delete 释放,new 和 delete 成对出现,尽量放在一个函数中

new 分配的内存都是动态分配的,不是在编译时分配

运算符 newnew[] 分别调用如下函数:

1
2
void * operator new (std::size_t); // used by new
void * operator new[] (std::size_t); // used by new[]

这些函数被称作分配函数,位于全局名称空间,同样也有 deletedelete[] 调用的释放函数

1
2
3
4
5
6
7
8
int *p = new int[3];
p[0] = 0;
p[1] = 1;
p[2] = 2;
cout << p[0] << endl; // 0
p = p + 1;
cout << p[0] << endl; // 1
delete [] p;

new 负责在堆(heap)中找到一个足以能够满足要求的内存块。但是 new 运算符还有另一种变体,定位 new 运算符,它让您能够指定要使用的位置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include ‹new> 
struct chaff
{
char dross [20];
int slag;
};

char buffer1 [50];
char buffer2 [500];

int main()
{
chaff *p1, *p2;
int *p3, *p4;
// first, the regular forms of new
p1 = new chaff; // place structure in heap
p3 = new int [20]; // place int array in heap
// now, the two forms of placement new
p2 = new (buffer1) chaff; // place structure in bufferl
p4 = new (buffer2) int[20]; // place int array in buffer2
}

但是不能用 delete 来释放 new 指定位置的内存,因为 buffer 指定的内存是静态内存

1
2
3
4
char * buffer = new char[BUF];
chaff *p1;
p1 = new (buffer) chaff;
delete []buffer; // 应该删除 buffer 所在的内存空间

allocator 类

new 将内存分配和对象构造组合在了一起,delete 将对象析构和内存释放组合在了一起。分配单个对象时,通常希望将内存分配和对象初始化组合在一起,但分配一大块内存时,通常计划在这块内存上按需构造对象,这时希望将内存分配和对象构造分离。

标准库 allocator 类定义在头文件 memory 中,它帮助我们将内存分配和对象构造分离,它分配的内存是原始的,未构造的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <memory>

// allocator 算法
allocator<T> a // 定义一个名为 a 的 allocator 对象,可以为类型 T 的对象分配内存
a.allocate(n) // 分配一段原始未构造内存,保存 n 个类型为 T 的对象
a.deallocate(p, n) // 释放从 p 地址开始的内存,该内存保存了 n 个 T 对象,p 必须是一个先前由 allocate 返回的指针,且 n 必须是 p 创建时所要求的大小,在调用 deallocate 之前,用户必须对每个在这块内存中创建的对象调用 destroy
a.construct(p, args) // 在 p 指向的内存中构造一个对象,新标准已弃用
a.destroy(p) // 对 p 指向的对象执行析构函数,新标准已弃用

// 例子
using namespace std;
int n = 7;
allocator<string> alloc; // 可以分配 string 的 allocator 对象
auto const p = alloc.allocate(n); // 分配 n 个未初始化的 string
auto q = p; // q 指向最后构造的元素之后的位置

for (int i = 0; i < n; ++i) {
p[i] = "qwt"; // 设置元素的值
}

alloc.deallocate(p, n); // 释放内存

标准库为 allocator 类定义了两个伴随算法用于拷贝和填充未初始化内存

1
2
3
4
5
6
#include <memory>

uninitialized_copy(b, e, p) // 从迭代器 b,e 之间拷贝元素至 p 指向的内存
uninitialized_copy_n(b, n, p) // 从迭代器 b 开始拷贝 n 个元素至 p
unintialized_fill(b, e, t) // 从迭代器 b,e 之间创建对象,对象的值为 t 的拷贝
unintialized_fill_n(b, n, t) // 从迭代器 b 开始创建 n 个对象