一。分配器allocator概述
分配器 (allocator) 是C++ STL库的基石之一,它是一种策略模式,允许用户将内存管理从容器中解耦出来,进行更具体化的操作。通过使用 allocator,我们可以自定义内存的分配和释放方式,从而可以更好地控制内存的使用。
分配器的使用和容器使用 紧密关联。
一般都是使用缺省的分配器
确切的叫做 内存分配器。扮演内存池的角色,但是不一定和内存池的技术一样,猜想一般通过大量减少对malloc()的调用,来节省内存,甚至还有效率的提高。
为何使用allocator
在C++中,内存的申请和释放是一个昂贵的操作,频繁的申请和释放可能导致系统的内存碎片,使程序性能下降。通过使用allocator,我们可以自定义内存的申请和释放方式,减少系统的内存碎片,提高程序的性能。
此外,allocator还有一个重要的作用,那就是将对象的构造和内存的申请分开。在传统的内存申请方式中,我们在申请内存的同时就会调用对象的构造函数,但有时候,我们可能只是想申请内存,而不想立即构造对象,这时候,就可以使用allocator。
二。分配器的使用
在C++ STL中,allocator是一个模板类,我们可以通过为它提供一个类型参数来创建一个特定类型的allocator。以下是一个基本的例子:
#include <memory>
int main() {
std::allocator<int> alloc; // 创建一个分配int的allocator
int* p = alloc.allocate(10); // 分配10个int的空间
// 使用未构造的内存
for (int i = 0; i < 10; ++i) {
alloc.construct(p + i, i); // 在分配的内存上构造对象
}
// 销毁对象并释放内存
for (int i = 0; i < 10; ++i) {
alloc.destroy(p + i); // 销毁对象
}
alloc.deallocate(p, 10); // 释放内存
return 0;
}
三。自定义分配器
C++ STL库的灵活性主要源于其策略模式的设计,分配器就是这种设计的一个重要应用。通过自定义分配器,我们可以实现一些特殊的内存管理策略,比如内存共享、内存泄漏探测,预分配对象存储、内存池等。
3.1 自定义分配器的应用场景
以下列出了一些自定义分配器的应用场景:
内存共享:对于多进程或者多线程应用,我们可能需要共享内存空间。自定义分配器可以使我们将对象存储在共享内存中。
内存泄漏探测:在复杂的应用中,内存泄漏可能是一个难以定位的问题。自定义分配器可以帮助我们追踪内存的分配和释放,从而检测内存泄漏。
预分配对象存储:对于一些知道内存需求的应用,预先分配内存可以避免频繁的内存分配和释放,提高性能。
内存池:对于频繁分配和释放小块内存的应用,使用内存池可以减少内存碎片,提高性能。
3.2 自定义分配器的实现
一个自定义分配器需要实现以下几个接口:
typedef:为使用的类型定义别名
allocate(n):分配能容纳n个对象的内存
deallocate(p, n):释放前面分配的内存
construct(p, val):在指针p所指向的内存上构造一个对象,其值为val
destroy(p):销毁指针p所指向的对象
template <class T>
class MyAllocator {
public:
typedef T value_type;
MyAllocator() = default;
template <class U> constexpr MyAllocator(const MyAllocator<U>&) noexcept {}
T* allocate(std::size_t n) {
// 你的内存分配策略
}
void deallocate(T* p, std::size_t) noexcept {
// 你的内存释放策略
}
template<typename... Args>
void construct(T* p, Args&&... args) {
// 你的对象构造策略
}
void destroy(T* p) {
// 你的对象销毁策略
}
};
template <class T, class U>
bool operator==(const MyAllocator<T>&, const MyAllocator<U>&) { return true; }
template <class T, class U>
bool operator!=(const MyAllocator<T>&, const MyAllocator<U>&) { return false; }
3.3 自定义分配器的使用
自定义分配器可以用于STL中的任何容器,包括vector、list等。以下是一个使用自定义分配器的vector的例子
#include <vector>
#include "MyAllocator.h" // 包含你的自定义分配器的头文件
int main() {
std::vector<int, MyAllocator<int>> vec; // 使用自定义分配器的vector
vec.push_back(1);
vec.push_back(2);
vec.push_back(3);
return 0;
}
在这个例子中,我们创建了一个使用MyAllocator
的std::vector
。因此,这个vector
的内存管理策略将由我们的MyAllocator
来决定。同样的方法也可以应用于std::list
或其他STL容器。