面试题答案
一键面试#include <memory>
#include <vector>
#include <iostream>
class MemoryPool {
public:
MemoryPool(size_t size) : pool(size) {}
void* allocate(size_t bytes) {
if (nextFreeIndex + bytes <= pool.size()) {
void* ptr = &pool[nextFreeIndex];
nextFreeIndex += bytes;
return ptr;
}
return nullptr;
}
void deallocate(void* ptr, size_t bytes) {
// 简单实现,这里假设只有一种大小的分配,且释放顺序与分配顺序相反
char* charPtr = static_cast<char*>(ptr);
if (charPtr >= &pool[0] && charPtr + bytes <= &pool[nextFreeIndex]) {
nextFreeIndex -= bytes;
}
}
private:
std::vector<char> pool;
size_t nextFreeIndex = 0;
};
template<typename T>
class PoolAllocator {
public:
using value_type = T;
PoolAllocator(MemoryPool& pool) : pool(pool) {}
template<typename U>
PoolAllocator(const PoolAllocator<U>& other) : pool(other.pool) {}
T* allocate(size_t n) {
return static_cast<T*>(pool.allocate(n * sizeof(T)));
}
void deallocate(T* p, size_t n) {
pool.deallocate(p, n * sizeof(T));
}
private:
MemoryPool& pool;
};
template<typename T, typename U>
bool operator==(const PoolAllocator<T>&, const PoolAllocator<U>&) {
return true;
}
template<typename T, typename U>
bool operator!=(const PoolAllocator<T>&, const PoolAllocator<U>&) {
return false;
}
内存泄漏风险分析及避免方法:
-
风险:
- 如果
MemoryPool::allocate
函数返回nullptr
(例如内存池空间不足),而调用者没有正确处理这种情况,可能会导致后续代码尝试使用空指针,这不是严格意义上的内存泄漏,但会导致程序崩溃。 - 在
MemoryPool::deallocate
函数中,如果释放的指针不在内存池的有效范围内,或者释放的大小与分配的大小不一致,可能会导致内存池内部状态混乱,后续分配可能出现错误,甚至可能出现内存访问越界等问题,间接导致内存泄漏。
- 如果
-
避免方法:
- 在调用
PoolAllocator::allocate
后,调用者应检查返回值是否为nullptr
,如果是,应进行适当处理(如抛出异常或返回错误码)。 - 在
MemoryPool::deallocate
函数中,可以增加更严格的边界检查,确保释放的指针确实是从该内存池分配的,并且大小与分配时一致。例如,可以在分配时记录每个分配块的大小和起始位置,在释放时进行验证。另外,对于释放顺序与分配顺序无关的复杂情况,可以使用更复杂的数据结构(如链表)来管理内存池中的空闲块。
- 在调用