1、C++的内存分配是一种类型化操作:new为特定类型分配内存,并在新分配的内存中构造该类型的一个对象。new表达式自动运行合适的构造函数来初始化每个动态分配的类类型对象。
2、在每种情况下(预先分配内存以保存用户级对象或者保留类的内部数据)都需要将内存分配与对象构造分离开。
3、C++提供下面两种方法分配和释放未构造的原始内存:
1)allocator类,它提供可感知类型的内存分配。这个类支持一个抽象接口,以分配内存并随后使用该内存保存对象。
2)标准库中的operator new和operator delete,它们分配和释放需要大小的原始的,未类型化的内存。
4、C++提供不同的方法在原始内存中构造和撤销对象:
1)allocator类定义了名为construct和destroy的成员,construct成员在未构造内存中初始化对象,destroy成员在对象上运行适当的析构函数。
2)定位new表达式(placement new expression)接受指向未构造内存的指针,并在该空间中初始化一个对象或一个数组。
3)可以直接调用对象的析构函数来撤销对象,运行析构函数并不释放对象所在的内存。
4)算法uninitialized_fill和uninitialized_copy像fill和copy算法一样执行,除了它们在目的地构造对象而不是给对象赋值之外。
5、现在C++程序一般应该使用allocator类来分配内存,它更安全更灵活。但是,在构造对象的时候,用new表达式比allocator::construct成员更灵活。
6、allocator类是一个模板,它提供类型化的内存分配以及对象构造与撤销。
标准allocator类与定制算法
allocator<T> a; 定义名为a的allocator对象,可以分配内存或构造T类型的对象
a.allocate(n) 分配原始的未构造内存以保存T类型的n个对象
a.deallocate(p,n) 释放内存,在名为p的T*指针中包含的地址处保存T类型的n个对象,运行调用deallocate之前在该内存中构造的任意对象的destroy是用户的责任
a.construct(p,t) 在T*指针p所指内存中构造一个新元素,运行T类型的赋值构造函数用t初始化该对象
a.destroy(p) 运行T*指针p所指对象的析构函数
uninitialized_copy(b,e,b2) 从迭代器b和e指出的输入范围将元素复制到从迭代器b2开始的未构造的原始内存中,该函数在目的地构造元素,而不是给它们赋值,假定由b2指出的目的地足以保存输入范围中元素的副本
uninitialized_fill(b,e,t) 将由迭代器b和e指出的范围中的对象初始化为t的副本,假定该范围是未构造的原始内存,使用复制构造函数构造对象
uninitialized_fill_n(b,e,t,n) 将由迭代器b和e指出的范围中至多n个对象初始化为t的副本,假定范围至少为n个元素大小,使用复制构造函数构造对象
7、operator new和operator delete函数有两个重载版本,每个版本支持相关的new表达式和delete表达式:
void *operator new(size_t) //allocate an object
void *operator new[](size_t) //allocate an array
void *operator delete(void*) //free an object
void *operator delete[](void*) //free an array
8、定位new表达式:定位new表达式在已分配的原始内存中初始化一个对象,它不分配内存,它接受指向已分配但未构造内存的指针,并在该内存中初始化一个对象。
定位new表达式的形式是:
new(place_address)type
new(place_address)type(initializer_list)
place_address必须是一个指针,而initializer_list(可能为空的)初始化列表,以便在构造新分配的对象时使用。
9、显式析构函数的调用:p->~T();
调用析构函数,析构函数以类名前加~来命名。
10、类成员operator new函数必须具有返回类型void*并接受size_t类型的形参,类成员operator delete函数必须具有返回类型void,它可以定义为接受单个void*类型形参,也可以定义为接受两个形参,即void*和size_t类型。成员new和delete函数必须是静态的。