实现一个简单的STL allocator

实现一个简单的STL allocator

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_ */

其中主要的接口及其作用如下:

  1. pointer allocate(size_type n, const void* hint = 0): 分配内存来存储n个类型为T的实例,并返回指向它的指针
  2. void deallocate(pointer p, size_type n): 释放分配的内存
  3. void construct(pointer p, const T& value): 使用p指向的value构造一个对象
  4. 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++内置的关键字,它主要做三件事:

  1. 调用对应的operator new操作符分配内存
  2. 调用对应的构造函数
  3. 返回构造对象类型的指针

delete是C++内置的关键字,它主要做两件事:

  1. 调用对应的析构函数
  2. 调用对应的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. 参考文献

  1. 侯捷,STL源码剖析
  2. https://github.com/mzh19940817/MyAllocator

欢迎大家批评指正、评论和转载(请注明源出处),谢谢!

hmoban主题是根据ripro二开的主题,极致后台体验,无插件,集成会员系统
自学咖网 » 实现一个简单的STL allocator