1. 概述
本文实现了一个简陋的allocator,并简单解释了new/delete的内部实现过程。
2. 一个简单的STL allocator
STL allocator是容器中的空间配置器,标准库默认的是std :: allocator。它的主要作用是内存分配与释放,对象构造和析构。它隐藏在容器内部,一般我们不需要关注,但了解其实现还是很有必要的。 实现的简陋allocator如下(详见参考文献1):
#ifndef MYALLOCATOR_H_
#define MYALLOCATOR_H_
#include <new>
#include <cstddef>
#include <cstdlib>
#include <climits>
#include <iostream>
namespace MA
{
template<typename T>
inline T* _allocate(ptrdiff_t size, T*)
{
T* tmp = static_cast<T*>(::operator new(static_cast<size_t>(size * sizeof(T))));
if(nullptr == tmp)
{
std::cerr << "out of memory" << std::endl;
}
return tmp;
}
template<typename T>
inline void _deallocate(T* buffer)
{
::operator delete(buffer);
}
template<typename T1, typename T2>
inline void _constructor(T1* p, const T2& value)
{
new(p) T1(value);
}
template<typename T>
inline void _destroy(T* p)
{
p->~T();
}
template<typename T>
struct allocator
{
using value_type = T;
using pointer = T*;
using const_pointer = const T*;
using reference = T&;
using const_reference = const T&;
using size_type = size_t;
using difference_type = ptrdiff_t;
template<typename U>
struct rebind
{
using other = allocator<U>;
};
pointer allocate(size_type n, const void* hint = 0)
{
return _allocate(static_cast<difference_type>(n), static_cast<pointer>(nullptr));
}
void deallocate(pointer p, size_type n)
{
_deallocate(p);
}
void construct(pointer p, const T& value)
{
_constructor(p, value);
}
void destroy(pointer p)
{
_destroy(p);
}
pointer address(reference x)
{
return static_cast<pointer>(&x);
}
const_pointer const_address(const_reference x)
{
return static_cast<const_pointer>(&x);
}
size_type max_size() const
{
return static_cast<size_type>(UINT_MAX / sizeof(T));
}
};
}
#endif /* MYALLOCATOR_H_ */
其中主要的接口及其作用如下:
- pointer allocate(size_type n, const void* hint = 0): 分配内存来存储n个类型为T的实例,并返回指向它的指针
- void deallocate(pointer p, size_type n): 释放分配的内存
- void construct(pointer p, const T& value): 使用p指向的value构造一个对象
- void destroy(pointer p): 调用p指向对象的析构函数
自定义allocator的使用如下(完整代码详见参考文献2):
#include "MyAllocator.h"
#include <vector>
#include "gtest/gtest.h"
struct MyAllocatorTest : testing::Test
{
};
TEST_F(MyAllocatorTest, test_for_my_allocator)
{
int arr[3] {1, 2, 3};
std::vector<int, MA::allocator<int>> vec{arr, arr + 3};
ASSERT_EQ(1, vec[0]);
ASSERT_EQ(2, vec[1]);
ASSERT_EQ(3, vec[2]);
}
3. new/delete简析
其中涉及到了内存分配与释放,对象构造和析构,这就要解释下new/delete了。 new是C++内置的关键字,它主要做三件事:
- 调用对应的operator new操作符分配内存
- 调用对应的构造函数
- 返回构造对象类型的指针
delete是C++内置的关键字,它主要做两件事:
- 调用对应的析构函数
- 调用对应的operator delete操作符释放内存
下面采用一个例子说明:
string *p = new string("Hello");
equals to:
void *memory = ::operator new(sizeof(string)); // 调用::operator new分配内存
string::string("Hello"); // 调用构造函数将字符串放到分配的内存
string *p = static_cast<string*>(memory); // 使p指针指向新构造的对象
delete p;
equals to:
p->string::~string("Hello"); // 调用析构函数
::operator delete(memory); // 调用::operator delete释放内存
4. 总结
本文通过一个简陋的allocator初探std::allocator的实现机制,能够对std::allocator有一个初步了解。当然这与实际的实现相差甚远,还需继续研究,更深入的剖析敬请期待。
5. 参考文献
- 侯捷,STL源码剖析
- https://github.com/mzh19940817/MyAllocator
欢迎大家批评指正、评论和转载(请注明源出处),谢谢!
|