STL之空间配置器(Allocator)

STL源码:分配器 allocator stl中allocator源码阅读,qt5.8版本,部分底层函数未学习到 阅读详情


本文以gcc_9.3.0为例

一、介绍

配置器的基本目的是为给定类型提供内存资源以及提供在内存不再需要时将其归还的地方。标准库的内存管理被封装在一个类模板中——allocator。

1.1、设计

C++标准对于该领域只是给出了一些指示,实现这些要求的最简单的方式是调用operator new和operator delete运算符。相比于有缓存的分配和可以重复利用之前分配的内存,这种方法可能会比较慢。但是这种方法可以在多种硬件和操作系统中正确地工作。__gnu_cxx::new_allocator实现了简单的operator new和operator delete语义,而__gun_cxx::malloc_allocator使用C语言的函数std::malloc和std::free实现了相同的功能。

另一种方法是在配置器类中使用智能来缓存分配。 这种额外的机制可以采用多种形式:位图索引,以2的指数级增长的存储桶的索引,或者更简单的固定大小缓存池。缓存可以在程序中的容器间共享。而且,也不总是调用operator new和operator delete来传递内存,这可以带来速度上的优势。使用这些技术的配置器是__gnu_cxx::bitmap_allocator,__gun_cxx::mt_alloc,和__gun_cxx::pool_allocator。1

1.2、使用

STL默认使用std::allocator配置器,而该配置器继承自__gnu_cxx::new_allocator。

vector< int > int_vec;

我们可以指定配置器:

vector<int,__gnu_cxx::malloc_allocator<int>> malloc_intvec;

1.3、扩展的配置器

  • 1、new_allocator:简单地包装::operator new 和::operator delete
  • 2、malloc_allocator:简单地包装malloc和free
  • 3、debug_allocator:在一个任意的配置器A外增加了一层包装。它将大小略有增加的请求传递给A,并使用额外的内存来存储尺寸大小信息。当将指针传递给deallocate()时,将检查存储的大小,并使用assert()确保它们匹配。
  • 4、throw_allocator:包含内存跟踪和标记功能
  • 5、__pool_alloc:高性能的单池配置器。可重用内存在类型相同实例之间共享。当列表(free list)被用完时,它将通过::operator new 获取新内存。如果客户容器请求的块超过某个阈值,则将绕过缓冲池,将分配请求直接传递给::operator new。
  • 6、__mt__alloc:高性能的固定尺寸的配置器,分配呈指数级增长。
  • 7、bitmap_allocator:一种高性能的配置器,使用位图来跟踪已经使用和未使用的内存位置。

二、C++内存操作

2.1、C++ 中的 new 和 delete

当我们使用一条new表达式时:

string *sp = new string("a value");
string *arr = new string[10];

实际执行了三步操作:

  • 第一步,new表达式调用operator new(或者operator new[ ])标准库函数。该函数分配一块足够大的、原始的、未命名的内存空间以便存储特定类型的对象(或者对象的数组)。
  • 第二步,编译器运行相应的构造函数以构造这些对象,并为其传入初始值。
  • 第三步,对象被分配了空间并构造完成,返回一个指向该对象的指针。

当我们使用一条delete表达式删除一个动态分配的对象时:

delete sp;
delete [] arr;

实际执行了两步操作:

  • 第一步,对sp所指向的对象或者arr所指的数组中的元素执行对应的析构函数。
  • 第二步,编译器调用名为operator delete(或者operator delete[ ])的标准库函数释放内存空间。2

2.2、STL内存配置

STL将new和delete的实现均分为两个阶段:

  • 内存配置由allocator::allocate()负责,内存释放由allocator::deallocate()负责
  • 对象构造由_Construct()负责,对象析构由_Destroy()负责

allocate和deallocate在不同的配置器中有不同的实现,_Construct和_Destroy则在stl_construct.h中实现。

三、对象构造和析构

3.1、对象构造

调用placement new

/**
* Constructs an object in existing memory by invoking an allocated
* object's constructor with an initializer.
*/
#if __cplusplus >= 201103L
template <typename _T1, typename... _Args>
inline void
_Construct(_T1 *__p, _Args &&... __args)
{
    ::new (static_cast<void *>(__p)) _T1(std::forward<_Args>(__args)...);
}
#else
template <typename _T1, typename _T2>
inline void
_Construct(_T1 *__p, const _T2 &__value)
{
    // _GLIBCXX_RESOLVE_LIB_DEFECTS
    // 402. wrong new expression in [some_]allocator::construct
    ::new (static_cast<void *>(__p)) _T1(__value);
}
#endif

3.2、对象析构

3.2.1 析构单个对象
/**
* Destroy the object pointed to by a pointer type.
*/
template <typename _Tp>
inline void
_Destroy(_Tp *__pointer)
{
    __pointer->~_Tp();
}
3.2.2 析构指定范围内的对象
3.2.2.1、_Destroy(_ForwardIterator __first, _ForwardIterator __last)
template <bool>
struct _Destroy_aux
{
    template <typename _ForwardIterator>
    static void
    __destroy(_ForwardIterator __first, _ForwardIterator __last)
    {
        for (; __first != __last; ++__first)
            std::_Destroy(std::__addressof(*__first));
    }
};

template <>
struct _Destroy_aux<true>
{
    template <typename _ForwardIterator>
    static void
        __destroy(_ForwardIterator, _ForwardIterator) {}
};

/**
* Destroy a range of objects.  If the value_type of the object has
* a trivial destructor, the compiler should optimize all of this
* away, otherwise the objects' destructors must be invoked.
*/
template <typename _ForwardIterator>
inline void
_Destroy(_ForwardIterator __first, _ForwardIterator __last)
{
    typedef typename iterator_traits<_ForwardIterator>::value_type
        _Value_type;
#if __cplusplus >= 201103L
    // A deleted destructor is trivial, this ensures we reject such types:
    static_assert(is_destructible<_Value_type>::value,
                  "value type is destructible");
#endif
    std::_Destroy_aux<__has_trivial_destructor(_Value_type)>::
        __destroy(__first, __last);
}
3.2.2.2、_Destroy_n(_ForwardIterator __first, _Size __count)
template <bool>
struct _Destroy_n_aux
{
    template <typename _ForwardIterator, typename _Size>
    static _ForwardIterator
    __destroy_n(_ForwardIterator __first, _Size __count)
    {
        for (; __count > 0; (void)++__first, --__count)
            std::_Destroy(std::__addressof(*__first));
        return __first;
    }
};

template <>
struct _Destroy_n_aux<true>
{
    template <typename _ForwardIterator, typename _Size>
    static _ForwardIterator
    __destroy_n(_ForwardIterator __first, _Size __count)
    {
        std::advance(__first, __count);
        return __first;
    }
};

/**
   * Destroy a range of objects.  If the value_type of the object has
   * a trivial destructor, the compiler should optimize all of this
   * away, otherwise the objects' destructors must be invoked.
   */
template <typename _ForwardIterator, typename _Size>
inline _ForwardIterator
_Destroy_n(_ForwardIterator __first, _Size __count)
{
    typedef typename iterator_traits<_ForwardIterator>::value_type
        _Value_type;
#if __cplusplus >= 201103L
    // A deleted destructor is trivial, this ensures we reject such types:
    static_assert(is_destructible<_Value_type>::value,
                  "value type is destructible");
#endif
    return std::_Destroy_n_aux<__has_trivial_destructor(_Value_type)>::
        __destroy_n(__first, __count);
}
3.2.2.3、_Destroy(_ForwardIterator __first, _ForwardIterator __last, _Allocator &__alloc)
/**
   * Destroy a range of objects using the supplied allocator.  For
   * nondefault allocators we do not optimize away invocation of 
   * destroy() even if _Tp has a trivial destructor.
   */

template <typename _ForwardIterator, typename _Allocator>
void _Destroy(_ForwardIterator __first, _ForwardIterator __last,
              _Allocator &__alloc)
{
    typedef __gnu_cxx::__alloc_traits<_Allocator> __traits;
    for (; __first != __last; ++__first)
        __traits::destroy(__alloc, std::__addressof(*__first));
}
3.2.2.4、_Destroy(_ForwardIterator __first, _ForwardIterator __last, allocator<_Tp> &)
template <typename _ForwardIterator, typename _Tp>
inline void
_Destroy(_ForwardIterator __first, _ForwardIterator __last,
         allocator<_Tp> &)
{
    _Destroy(__first, __last);
}

3.3 _Construct和_Destroy示意

_Construct
::new(static_cast (__p)) _T1
Destroy
单个对象
_Destroy(_Tp* __pointer)
__pointer->~_Tp()
对象范围
_Destroy(_ForwardIterator __first, _ForwardIterator __last)
_Destroy_n(_ForwardIterator __first, _Size __count)
_Destroy(_ForwardIterator __first, _ForwardIterator __last, _Allocator& __alloc)
_Destroy(_ForwardIterator __first, _ForwardIterator __last, allocator<_Tp>&)
std::_Destroy_aux::__destroy(__first, __last)
std::_Destroy_n_aux::__destroy_n
__traits::destroy
_Destroy(__first, __last)

四、具体配置器示例

4.1、new_allocator

文件位置:libstdc++ -v3\include\ext\new_allocator.h
简要介绍:只是将operator new和operator delete做了简单的包装

allocate的实现如下:

pointer
allocate(size_type __n, const void * = static_cast<const void *>(0))
{
    if (__n > this->max_size())
        std::__throw_bad_alloc();

#if __cpp_aligned_new
    if (alignof(_Tp) > __STDCPP_DEFAULT_NEW_ALIGNMENT__)
    {
        std::align_val_t __al = std::align_val_t(alignof(_Tp));
        return static_cast<_Tp *>(::operator new(__n * sizeof(_Tp), __al));
    }
#endif
    return static_cast<_Tp *>(::operator new(__n * sizeof(_Tp)));
}

deallocate的实现如下:

void deallocate(pointer __p, size_type)
{
#if __cpp_aligned_new
    if (alignof(_Tp) > __STDCPP_DEFAULT_NEW_ALIGNMENT__)
    {
        ::operator delete(__p, std::align_val_t(alignof(_Tp)));
        return;
    }
#endif
    ::operator delete(__p);
}

4.2、__pool_alloc

文件位置:libstdc++ -v3\include\ext\pool_allocator.h
简要介绍:若请求的区块大小超过128bytes时,直接调用operator new处理。当区块小于128bytes时,则以内存池管理:每次配置一大块内存,并维护对应的自由链表(free_list)。下次,若再有相同大小的内存需求,就直接从free_list中分配。如果归还区块,则由配置器回收到free_list中。为了方便管理,配置器会将任何区块的内存需求量上调至8的倍数,并维护16个free_lists。

template<typename _Tp>
    class __pool_alloc : private __pool_alloc_base

在__pool_alloc_base中维护一个内存池

    class __pool_alloc_base
    {
    protected:

      enum { _S_align = 8 };
      enum { _S_max_bytes = 128 };
      enum { _S_free_list_size = (size_t)_S_max_bytes / (size_t)_S_align };
      
      union _Obj
      {
	      union _Obj* _M_free_list_link;
	      char        _M_client_data[1];    // The client sees this.
      };
      
      static _Obj* volatile         _S_free_list[_S_free_list_size];

      // Chunk allocation state.
      static char*                  _S_start_free;
      static char*                  _S_end_free;
      static size_t                 _S_heap_size;     
      
      size_t
      _M_round_up(size_t __bytes)
      { return ((__bytes + (size_t)_S_align - 1) & ~((size_t)_S_align - 1)); }
      
      _GLIBCXX_CONST _Obj* volatile*
      _M_get_free_list(size_t __bytes) throw ();
    
      __mutex&
      _M_get_mutex() throw ();

      // Returns an object of size __n, and optionally adds to size __n
      // free list.
      void*
      _M_refill(size_t __n);
      
      // Allocates a chunk for nobjs of size size.  nobjs may be reduced
      // if it is inconvenient to allocate the requested number.
      char*
      _M_allocate_chunk(size_t __n, int& __nobjs);
    };

4.2.1、allocate()

template <typename _Tp>
_Tp *__pool_alloc<_Tp>::allocate(size_type __n, const void *)
{
    pointer __ret = 0;
    if (__builtin_expect(__n != 0, true))
    {
        if (__n > this->max_size())
            std::__throw_bad_alloc();

        const size_t __bytes = __n * sizeof(_Tp);

#if __cpp_aligned_new
        if (alignof(_Tp) > __STDCPP_DEFAULT_NEW_ALIGNMENT__)
        {
            std::align_val_t __al = std::align_val_t(alignof(_Tp));
            return static_cast<_Tp *>(::operator new(__bytes, __al));
        }
#endif

        // If there is a race through here, assume answer from getenv
        // will resolve in same direction.  Inspired by techniques
        // to efficiently support threading found in basic_string.h.
        if (_S_force_new == 0)
        {
            if (std::getenv("GLIBCXX_FORCE_NEW"))
                __atomic_add_dispatch(&_S_force_new, 1);
            else
                __atomic_add_dispatch(&_S_force_new, -1);
        }
        //大于128bytes,直接调用operator new
        if (__bytes > size_t(_S_max_bytes) || _S_force_new > 0)
            __ret = static_cast<_Tp *>(::operator new(__bytes));
        else
        {
            _Obj *volatile *__free_list = _M_get_free_list(__bytes);

            __scoped_lock sentry(_M_get_mutex());
            _Obj *__restrict__ __result = *__free_list;
            if (__builtin_expect(__result == 0, 0))
                //没有找到合适的__free_list,重新填充
                __ret = static_cast<_Tp *>(_M_refill(_M_round_up(__bytes)));
            else
            {
                *__free_list = __result->_M_free_list_link;
                __ret = reinterpret_cast<_Tp *>(__result);
            }
            if (__ret == 0)
                std::__throw_bad_alloc();
        }
    }
    return __ret;
}
4.2.1.1、 __M_refill()
// Returns an object of size __n, and optionally adds to "size
// __n"'s free list.  We assume that __n is properly aligned.  We
// hold the allocation lock.
void *
__pool_alloc_base::_M_refill(size_t __n)
{
    int __nobjs = 20;//默认取20个区块
    char *__chunk = _M_allocate_chunk(__n, __nobjs);
    _Obj *volatile *__free_list;
    _Obj *__result;
    _Obj *__current_obj;
    _Obj *__next_obj;

    if (__nobjs == 1)
        return __chunk;
    __free_list = _M_get_free_list(__n);

    // Build free list in chunk.
    __result = (_Obj *)(void *)__chunk;
    *__free_list = __next_obj = (_Obj *)(void *)(__chunk + __n);
    for (int __i = 1;; __i++)
    {
        __current_obj = __next_obj;
        __next_obj = (_Obj *)(void *)((char *)__next_obj + __n);
        if (__nobjs - 1 == __i)
        {
            __current_obj->_M_free_list_link = 0;
            break;
        }
        else
            __current_obj->_M_free_list_link = __next_obj;
    }
    return __result;
}
4.2.1.2、 _M_allocate_chunk()
// Allocate memory in large chunks in order to avoid fragmenting the
// heap too much.  Assume that __n is properly aligned.  We hold the
// allocation lock.
char *
__pool_alloc_base::_M_allocate_chunk(size_t __n, int &__nobjs)
{
    char *__result;
    size_t __total_bytes = __n * __nobjs;
    size_t __bytes_left = _S_end_free - _S_start_free;

    if (__bytes_left >= __total_bytes)
    {//内存池剩余空间完全满足需要
        __result = _S_start_free;
        _S_start_free += __total_bytes;
        return __result;
    }
    else if (__bytes_left >= __n)
    {//内存池剩余空间不能完全满足需要,但足够分配一个及以上的区块
        __nobjs = (int)(__bytes_left / __n);
        __total_bytes = __n * __nobjs;
        __result = _S_start_free;
        _S_start_free += __total_bytes;
        return __result;
    }
    else
    {//内存池剩余空间连一个区块大小都不能满足
        // Try to make use of the left-over piece.
        if (__bytes_left > 0)
        {//将剩余的空间分配到合适的_S_free_list中
            _Obj *volatile *__free_list = _M_get_free_list(__bytes_left);
            ((_Obj *)(void *)_S_start_free)->_M_free_list_link = *__free_list;
            *__free_list = (_Obj *)(void *)_S_start_free;
        }

        size_t __bytes_to_get = (2 * __total_bytes + _M_round_up(_S_heap_size >> 4));
        __try
        {
            _S_start_free = static_cast<char *>(::operator new(__bytes_to_get));
        }
        __catch(const std::bad_alloc &)
        {//heap剩余空间不足,::operate new失败
        //1、从_S_free_list中找出有剩余内存的且大于等于__n的最小的链
        //2、从中分配__n大小的内存,同时修改_S_start_free和_S_end_free
        //3、递归调用_M_allocate_chunk时,将多余的内存放入适合的_S_free_list中
            // Try to make do with what we have.  That can't hurt.  We
            // do not try smaller requests, since that tends to result
            // in disaster on multi-process machines.
            size_t __i = __n;
            for (; __i <= (size_t)_S_max_bytes; __i += (size_t)_S_align)
            {
                _Obj *volatile *__free_list = _M_get_free_list(__i);
                _Obj *__p = *__free_list;
                if (__p != 0)
                {
                    *__free_list = __p->_M_free_list_link;
                    _S_start_free = (char *)__p;
                    _S_end_free = _S_start_free + __i;
                    return _M_allocate_chunk(__n, __nobjs);
                    // Any leftover piece will eventually make it to the
                    // right free list.
                }
            }
            // What we have wasn't enough.  Rethrow.
            _S_start_free = _S_end_free = 0; // We have no chunk.
            __throw_exception_again;
        }
        //::operator new成功,修改_S_heap_size、_S_end_free
        //递归调用_M_allocate_chunk,完成分配
        _S_heap_size += __bytes_to_get;
        _S_end_free = _S_start_free + __bytes_to_get;
        return _M_allocate_chunk(__n, __nobjs);
    }
}
4.2.1.3、 allocate()流程图

在这里插入图片描述

4.2.2、 deallocate()

template <typename _Tp>
void __pool_alloc<_Tp>::deallocate(pointer __p, size_type __n)
{
    if (__builtin_expect(__n != 0 && __p != 0, true))
    {
#if __cpp_aligned_new
        if (alignof(_Tp) > __STDCPP_DEFAULT_NEW_ALIGNMENT__)
        {
            ::operator delete(__p, std::align_val_t(alignof(_Tp)));
            return;
        }
#endif
        const size_t __bytes = __n * sizeof(_Tp);
        if (__bytes > static_cast<size_t>(_S_max_bytes) || _S_force_new > 0)
            ::operator delete(__p);
        else
        {
            _Obj *volatile *__free_list = _M_get_free_list(__bytes);
            _Obj *__q = reinterpret_cast<_Obj *>(__p);

            __scoped_lock sentry(_M_get_mutex());
            __q->_M_free_list_link = *__free_list;
            *__free_list = __q;
        }
    }
}

  1. https://gcc.gnu.org/onlinedocs/libstdc++/manual/memory.html#std.util.memory.allocator ↩︎

  2. C++ primer,中文版,第5版 ↩︎

STL 空间配置器 allocator `STL` 空间配置器 `allocator``STL` 标准下的 `allocator`神奇的 `SGI STL``SGI` 里效率低下的 `std::allocator``SGI` 里正规的 `std::alloc`构造 `construct()` & 析构 `destroy()``alloc` 设计哲学`alloc` 的第一级配置器:`__malloc_alloc_template``alloc` 的第二级配置器:`__default_alloc_template` 无私奉献的 alloca 阅读详情

相关推荐

1014. 福尔摩斯的约会 (20)-PAT乙级真题

1014. 福尔摩斯的约会 (20) 大侦探福尔摩斯接到一张奇怪的字条:“我们约会吧!3485djDkxh4hhGE 2984akDfkkkkggEdsb s&hgsfdk d&Hyscvnm”。大侦探很快就明白了,字条上奇怪的乱码实际上就是约会的时间“星期四 14:04”,因为前面两字符串中第1对相同的大写英文字母(大小写有区分)是第4个字母’D’,代表星期四;第2对相同的字符是’

柳婼 の blog 2646

深入C++的new

“new”是C++的一个关键字,同时也是操作符。关于new的话题非常多,因为它确实比较复杂,也非常神秘,下面我将把我了解到的与new有关的内容做一个总结。new的过程当我们使用关键字new在堆上动态创建一个对象时,它实际上做了三件事:获得一块内存空间、调用构造函数、返回正确的指针。当然,如果我们创建的是简单类型的变量,那么第二步会被省略。假如我们定义了如下一个类A:class A{  

宋久擎的BLOG 15万+

HDMI2.1 FRL流控 概览

HDMI 2.1 FRL的流控本质是。

叫好与叫座虽然不是对立面,但想在同一个作品中达到双重效果很难。 2083

重写allocate

allocate重写简要 一般STL库里的容器都会使用allocator来分配内存 实现自己的allocator可以达到让容器使用自身的内存管理 实现allocator不必重载allocator类,随便开一个新类即可 allocator有五个必须有的函数 allocate: 用于开辟内存,功能类似operator new deallocate: 回收内存,功能类似operator delete construct: 调用构造函数 destroy: 调用释构函数 重绑用的拷贝函数 template

Eugen009的博客 538

华为防火墙双线路配置实战:5分钟搞定主备自动切换(含健康检查避坑指南)

本文详细介绍了华为防火墙双线路配置实战,包括主备自动切换和健康检查机制的优化技巧。通过智能健康检查机制,华为防火墙能实现毫秒级故障自动切换,确保网络高可用性。文章提供了从架构设计到实战配置的全流程指南,并分享了常见配置误区与解决方案,帮助中小企业快速搭建稳定可靠的网络架构。

weixin_30872337的博客 605

AI漫剧全套万能提示词合集

今天给大家整理一套已经跑通爆款漫剧的万能提示词库!覆盖:豆包剧本人设词 + 分镜生成词 + 即梦绘图词 + 动态优化词 + 防翻车固定词直接复制粘贴,新手也能做出稳定、高清、统一、有质感的AI漫剧!你是资深短视频漫剧编剧,擅长制作60秒竖屏爆款AI漫剧,请为我创作一集完整漫剧内容。要求:开头3秒高能抓眼,中段有冲突转折,结尾留强悬念钩子,节奏紧凑、适合短视频流量。首先生成固定统一人物人设:包含脸型、五官、发色、发型、穿搭、身材、气质、画风、光影细节,要求足够精细,保证全程角色不变脸。

欢迎来到鸾姝淡月博客,专为程序员和编程爱好者打造的技术博客。我们分享编程语言趋势、开发工具、编程哲学、职业发展等,助你掌握新技术,优化技能,激发编程热情。 1899

STL源码剖析(侯捷版本) —— 第二章 空間配置器 allocator(一)

在 STL 的使用中,空间配置器是用户“不需要关注”的部分。它始终隐藏在 STL 组件(如容器)的背后,默默完成内存分配和管理的任务。用户使用 STL 容器时,很少直接接触空间配置器的细节。STL 的 Allocator 是一个标准化的内存分配接口,定义了类型别名、内存分配与释放,以及对象构造与销毁的功能。它通过泛型和嵌套类型支持不同对象类型的内存管理,是 STL 容器内存操作的核心工具。allocator::value_type:分配的对象类型。

weixin_42255569的博客 1718

3.摄像头组件- CVP (ISP)

本文介绍 车载摄像头组件-ISP

2401_83458819的博客 1617

一篇文章搞懂STL中的空间配置器allocator(原创,多图,易懂)

Table of Contents 0.引入 1.标准的空间配置器allocator 2.更为高效的空间配置器alloc 2.1----对象的构造与析构 2.1.1 对象的构造:::construct(); 2.1.2对象的析构:::destroy(); 2.2----内存的配置与释放 2.2.0 概述 2.2.1一级配置器:__malloc_alloc_template 2...

vjhghjghj的博客 4816

Android14 SystemUI如何实现下拉菜单栏高斯模糊背景效果(类似于毛玻璃效果)

我们都知道,从Android12起,下拉菜单栏控制中心都是黑色的,看起来非常不美观,而且国内的手机系统UI都做的比较美观,大部分的下拉菜单UI背景都是实现了高斯模糊效果,所以客户也会要求实现类似于这样的效果。在以前的Android项目中,实现下拉菜单栏的模糊背景就是通过截图的方式进行替换背景,而这种方式下拉菜单背景极易替换不了,就算是在各个地方都适配,还是有概率在复杂场景或者一些测试手法下出现背景是黑的情况,并且这种方式还比较影响性能,毕竟每次都要去截图一次,多做了额外的事。

热衷于Android Framework和系统APP的修改经验分享 1793

mjlab & MimicKit 宇树 G1 人形机器人强化学习训练部署

基于mjlab框架训练Unitree G1人形机器人执行双旋踢的示例。参考动作源自Jason Peng的MimicKit项目。数据转换脚本(MimicKit pkl → mjlab csv)完整训练结果与超参数预训练ONNX检查点用于部署实体硬件部署指南⚠️ 免责声明仅用于教育目的。对于因尝试复现此处展示结果而导致的财产损失或人身伤害,我们概不负责。操作硬件时请谨慎行事并保持良好判断力。

2506_90492529的博客 1700

C++ STL标准库:空间配置器allocator

文章目录1. 前言2. 为什么需要空间配置器?3. allocator类模板 1. 前言 STL中每个容器的第二个模板参数都是 allocator类型而且默认参数都是 allocator explicit vector (const allocator_type& alloc = allocator_type()); explicit list (const allocator_type& alloc = allocator_type()); template <> class

超级大洋葱的博客 932

极智芯 | 解读国产CPU之海光

大家好,我是极智视界,本文分享一下 解读国产CPU之海光。希望我的分享能对你的学习有一点帮助。

极智视界 3319

STL学习笔记——空间配置器(allocator)

STL学习笔记——空间配置器(allocator)

weixin_48956191的博客 402

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

STL-空间配置器(allocator)

SGI空间配置器allocator的标准接口allocator::value_type allocator::pointer allocator::const_pointer allocator::reference allocator::const_reference allocator::size_type allocator::diffrence_type allocator::rebind

Linkin_ygw的博客 636

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

【STL源码剖析】【2、空间配置器——allocator】

【STL源码剖析】【2、空间配置器——allocator】

zwh1298454060的博客 1435

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

STL空间配置器allocator详解

stl六大组件简介我们知道,stl有容器,空间配置器,适配器,迭代器,仿函数以及算法这6个组件,它们六者关系大概如下:容器通过配置器取得数据存储空间,算法通过迭代器获取容器内容,仿函数可以协助算法完成不同的策略变化,配接器可以修饰或套界仿函数。侯捷在《STL源码剖析》一书讲到:因此我们需要先去学习空间配置器。预备知识一般来说,我们习惯的C++内存配置和释放操作是这样的:class A {}; A*

xy913741894的博客 1万+

STL学习笔记--2、空间配置器 allocator

STL allocator alloc

Cherryuuuu 3285

C++ STL源码解析:空间配置器(allocator)

C++ STL空间配置器std::allocator的 原码解析,主要解析allocate底层的一级空间配置器、二级空间配置器

slzz_的博客 924

【STL】SGI空间配置器 Allocator

本篇将主要总结归纳《STL源码剖析》的空间配置器的相关STL实现。在此之前,我们也将总结归纳一些基本的C++知识和技法。 一、C++基础知识--3种new的方式 在C++中,包含3种new形式,分别是  new / delete operator new / operator delete placement new    在C++中,我们所习惯的C++内存配置操作和释放

小do在努力 721

【STL2】空间配置器allocator

目录 标准模板库 1.空间配置器allocator总述 2.空间配置器标准接口 3.二级空间配置器 标准模板库 1.空间配置器allocator总述 标准模板库中利用空间配置器来在幕后管理内存空间。之所以叫空间配置器,是因为可能在某种情况下,可以在内存以外的介质比如硬盘上进行分配。不过一般来讲是内存,有下面两种空间配置器。 一种是标准的空间配置器,std:allocator //包含在xmemory头文件,对::operator new和::operator delete的简单封装 一种是

飞舞哲 426

STL 学习之空间配置器(allocator)

空间配置器(allocator)  学习(一)allocator必要接口以及SGI的第一级配置器    allocator不一定操作内存,也可以直接向硬盘取空间。    简单说就是管理容器的资料的空间的工具。    根据规范,allocator的必要接口为:    allocator::value_type allocator::pointer allocator::const_pointer a...

zxzamt的博客 581

STL空间配置器(Allocator)

大内存直接依赖mallocfree,简单高效;小内存通过“内存池+空闲链表”减少碎片,提升复用率。这种设计完美体现了STL“效率优先”的哲学——在抽象内存管理的同时,通过针对性优化(如对齐、内存池)确保“零抽象开销”,让容器的内存操作既灵活又高效。

u010632343的博客 803

STL之空间配置器allocator

以STL的运用角度而言,空间配置器是最不需要介绍的东西,它总是隐藏在一切组件(更具体的说是指容器,container)的背后,默默的工作,默默付出。但若以STL的实现角度而言,第一个需要介绍的就是空间配置器,因为整个STL的操作对象(所有的数值)都存放在容器之内,而容器一定需要配置空间以放置资料。不先掌握空间配置器的原理,难免在阅读其它STL组件的实现时处处遇到挡路石。为什么不说allocator是内存配置器而说它是空间配置器呢?因为空间不一定是内存,空间也可以是磁盘或其它辅助存储介质。

chnming1987的博客 1282
上一篇: C++ STL概论
下一篇: STL之迭代器(Iterator)
Spring_24
博客等级 码龄12年 46粉丝 41原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Spring_24

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值