C++ STL中的allocator
admin
2024-01-16 21:50:55

绪论

As we all kown,C++中的STL容器使用其内置的std::allocator分配内存。如果我们想要更改STL分配内存的行为,我们不用更改容器的逻辑,只需要更改传入的allocator即可。一直以来,allocator对我来讲都笼罩着一层迷雾,总感觉是一个很复杂很恐怖的东西,最近因为课程原因,需要使用平台特定的内存管理函数(在NVM仿真平台quartz中需要使用其提供的pmalloc和pfree函数管理非易失性内存),就研究了一下std::allocator是怎么实现的。但是认真了解以后发现没有什么神奇的东西。

源码剖析

allocator主要有四个接口:

  • T *allocate(size_t):用void * ::operator new(size_t)分配内存(但是不构造,其实就是对malloc的封装)
  • void deallocate(T*, size_t):使用void ::operator delete(void *)释放内存(其实是对free的封装)
  • void construct(T*, Args&&):使用定位new(placement new::new(void*) T(std::forward(args)...))在指定内存上进行构造
  • void destroy(T*):调用析构函数(p->~T())进行析构

不过后两者在C++17中被废弃了,在C++20中被删除了,我在stackoverflow上看到一个回答的大概意思是以后应该用std::allocator_traits::construct了。原回答:Why are are std::allocator’s construct and destroy functions deprecated in c++17?

去看了一下STL 的源码,发现std::allocator继承了__allocator_base,然后后者又继承了__gnu_cxx::new_allocator,也就是说其实用的是GNU版本的allocator,我认真阅读了一下__gnu_cxx::new_allocator的实现,发现的确挺简洁,没有什么特殊的东西,通过把里面的宏改成普通的关键字,删除掉我觉得没有什么用的版本判断,就可以得到一个简单的allocator实现:

// Copyright(C), Edward-Elric233
// Author: Edward-Elric233
// Version: 1.0
// Date: 2022/10/25
// Description: __gnu__cxx::new_allocator
#ifndef TEMP_PALLOCATOR_H
#define TEMP_PALLOCATOR_H#include "utils.h"
#include 
#include namespace edward
{using std::size_t;using std::ptrdiff_t;/***  @brief  An allocator that uses global new, as per [20.4].*  @ingroup allocators**  This is precisely the allocator defined in the C++ Standard.*    - all allocation calls operator new*    - all deallocation calls operator delete**  @tparam  T  Type of allocated object.*/templateclass pallocator{public:typedef size_t     size_type;typedef ptrdiff_t  difference_type;typedef T*       pointer;typedef const T* const_pointer;typedef T&       reference;typedef const T& const_reference;typedef T        value_type;templateusing other = pallocator;// _GLIBCXX_RESOLVE_LIB_DEFECTS// 2103. propagate_on_container_move_assignmenttypedef std::true_type propagate_on_container_move_assignment;constexpr pallocator() noexcept { }constexprpallocator(const pallocator&) noexcept { }templateconstexprpallocator(const pallocator&) noexcept { }~pallocator() noexcept { }pointeraddress(reference __x) const noexcept{ return std::__addressof(__x); }const_pointeraddress(const_reference __x) const noexcept{ return std::__addressof(__x); }// NB: __n is permitted to be 0.  The C++ standard says nothing// about what the return value is when __n == 0.[[nodiscard]] pointer   //cannot discard return value!!!allocate(size_type __n, const void* = static_cast(0)){if (__n > this->max_size())throw std::bad_alloc();print("allocate", __n * sizeof(T), "bytes");return static_cast(::operator new(__n * sizeof(T)));}// __p is not permitted to be a null pointer.voiddeallocate(pointer __p, size_type __n){print("deallocate", __n * sizeof(T), "bytes");::operator delete(__p);}size_typemax_size() const noexcept{return size_t(__PTRDIFF_MAX__) / sizeof(T);}templatevoidconstruct(_Up* __p, _Args&&... __args)noexcept(std::is_nothrow_constructible<_Up, _Args...>::value){ ::new((void *)__p) _Up(std::forward<_Args>(__args)...); }templatevoiddestroy(_Up* __p)noexcept(std::is_nothrow_destructible<_Up>::value){ __p->~_Up(); }templatefriend booloperator==(const pallocator&, const pallocator<_Up>&) noexcept{ return true; }templatefriend booloperator!=(const pallocator&, const pallocator<_Up>&) noexcept{ return false; }};} // namespace#endif //TEMP_PALLOCATOR_H

我在allocatedeallocate函数中添加了打印函数,utils.h头文件的获取可以看一下我之前的博客:C++ 工具函数库

参考资料

  • 第10篇:C++ 堆内存管理器-allocator
  • 《C++ primer》第5版 12.2.2节 allocator类

上一篇:用智慧捉贼

下一篇:厕所的独白

相关内容

热门资讯

大年初九云南人走亲访友喜欢带什... 春节拜年有什么讲究拜年一般从家里开始。初一早晨,晚辈起床后,要先向长辈拜年,祝福长辈健康长寿,万事如...
一块面团的千年旅程:从“炕头艺... 在山西省闻喜县,每年春节前后,订花馍、做花馍成为家家户户的一件“大事”。大大小小的花馍铺忙得不可开交...
大年初九黑龙江人走亲访友喜欢带... 一、过年拜年送什么好:送亲戚中长辈的礼物  正月初三开始,走亲戚的顺序就自由选择了。如果给亲戚中的长...
大年初九青海人走亲访友喜欢带什... 一、过年拜年送什么好:送亲戚中长辈的礼物  正月初三开始,走亲戚的顺序就自由选择了。如果给亲戚中的长...
大年初九甘肃人走亲访友喜欢带什... 春节拜年礼品选择一、送给亲友的春节礼物  1.以贺新年、庆吉利、添富有为内容的盆栽,再装饰一些艳丽别...