std::allocator_traits 能做但 std::allocator 不能的事情

🌟 std::allocator_traits 能做但 std::allocator 不能的事情

1️⃣ 适配自定义分配器

假设你要实现一个内存池 MyAllocator,而 STL 容器默认使用的是 std::allocator
如果你希望 STL 容器可以使用你的 MyAllocator,你 不能直接用 std::allocator,但可以通过 std::allocator_traits 让你的 MyAllocator 兼容 STL。

🚀 代码示例:
#include <iostream>
#include <memory>
#include <vector>

template <typename T>
class MyAllocator {
public:
    using value_type = T;

    T* allocate(std::size_t n) {
        std::cout << "Allocating " << n << " objects\n";
        return static_cast<T*>(::operator new(n * sizeof(T)));
    }

    void deallocate(T* p, std::size_t) {
        std::cout << "Deallocating objects\n";
        ::operator delete(p);
    }
};

int main() {
    std::vector<int, MyAllocator<int>> vec;  // 使用自定义分配器
    vec.push_back(10);  // std::allocator_traits 让 vec 兼容 MyAllocator
    vec.push_back(20);
}

std::allocator_traits 使 std::vector 兼容 MyAllocator,而 std::allocator 无法做到这一点


2️⃣ rebind 机制:不同类型对象之间的分配

std::allocator 时代,如果你有一个 Allocator<int>,但你想用它来分配 double,你需要手动定义 rebind

template <typename T>
struct MyAllocator {
    using value_type = T;

    template <typename U>
    struct rebind { using other = MyAllocator<U>; };
};

问题:

  • std::allocator<int> 不能直接用于 std::allocator<double>
  • 你必须手动实现 rebind,增加了额外的代码和复杂度。

解决方案:std::allocator_traits 自动提供 rebind

template <typename T>
class MyAllocator {
public:
    using value_type = T;
    T* allocate(std::size_t n) { return static_cast<T*>(::operator new(n * sizeof(T))); }
    void deallocate(T* p, std::size_t) { ::operator delete(p); }
};

int main() {
    using Alloc = MyAllocator<int>;
    using ReboundAlloc = std::allocator_traits<Alloc>::rebind_alloc<double>; // 绑定到double
    ReboundAlloc alloc; 
    double* p = alloc.allocate(5);  // 现在可以分配 double 了!
    alloc.deallocate(p, 5);
}

std::allocator_traits 自动提供 rebind,避免手写 rebind 逻辑!


3️⃣ constructdestroy 适配自定义指针

std::allocator 时代,construct() 直接调用 new,但是如果你有一个 自定义指针(比如智能指针),你就会发现 std::allocator 无法直接适配。

问题:

  • std::allocator::construct() 只能用于普通指针 T*,不支持 std::unique_ptr<T>std::shared_ptr<T>
  • std::allocator 不支持使用 std::shared_ptr 作为 pointer 类型

解决方案:使用 std::allocator_traits 适配智能指针

#include <iostream>
#include <memory>

template <typename T>
struct SmartAllocator {
    using value_type = T;
    using pointer = std::unique_ptr<T>; // 使用 unique_ptr 而不是裸指针

    T* allocate(std::size_t n) {
        return static_cast<T*>(::operator new(n * sizeof(T)));
    }

    void deallocate(T* p, std::size_t) {
        ::operator delete(p);
    }
};

int main() {
    SmartAllocator<int> alloc;
    using AllocTraits = std::allocator_traits<SmartAllocator<int>>;

    int* p = AllocTraits::allocate(alloc, 1);
    AllocTraits::construct(alloc, p, 42);
    
    std::cout << "Constructed value: " << *p << std::endl;

    AllocTraits::destroy(alloc, p);
    AllocTraits::deallocate(alloc, p, 1);
}

std::allocator_traits 使得 SmartAllocator 可以支持 unique_ptr,而 std::allocator 无法支持!


4️⃣ 适配 constexpr 分配器

在现代 C++ 中,某些分配器需要支持 constexpr,而 std::allocator 不能被 constexpr 调用。但 std::allocator_traits 可以提供 constexpr 支持

template <typename T>
struct ConstexprAllocator {
    using value_type = T;

    constexpr T* allocate(std::size_t n) {
        return new T[n];
    }

    constexpr void deallocate(T* p, std::size_t) {
        delete[] p;
    }
};

constexpr int test() {
    ConstexprAllocator<int> alloc;
    using AllocTraits = std::allocator_traits<ConstexprAllocator<int>>;

    int* p = AllocTraits::allocate(alloc, 1);
    AllocTraits::construct(alloc, p, 42);
    int val = *p;
    AllocTraits::destroy(alloc, p);
    AllocTraits::deallocate(alloc, p, 1);

    return val;
}

static_assert(test() == 42, "Test failed");

std::allocator_traits 使得 ConstexprAllocator 可以支持 constexpr,而 std::allocator 无法支持!


🎯 总结:std::allocator_traits 相比 std::allocator 的优越性

特性std::allocatorstd::allocator_traits
适配自定义 Allocator❌ 不支持✅ 适配 MyAllocator
支持 rebind 机制❌ 需要手写 rebind✅ 自动提供 rebind
支持智能指针❌ 不支持✅ 可以适配 unique_ptr
适配 constexpr❌ 不能 constexpr✅ 支持 constexpr
统一 STL 分配接口❌ STL 不能通用vectormap 都能用

🚀 什么时候必须用 std::allocator_traits

  1. 你在实现自定义 Allocator,并想让 STL 容器使用它。
  2. 你需要在 Allocator 中使用 unique_ptrshared_ptr
  3. 你想要 Allocator 适用于不同类型的对象(使用 rebind)。
  4. 你希望 Allocatorconstexpr 计算时可以工作。

🔥 结论

虽然 std::allocator 仍然在某些简单场景下可用,但现代 C++ 开发 几乎所有 STL 容器 都依赖 std::allocator_traits,而 std::allocator 已经不再直接使用。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/980258.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Python 初级函数详解】—— 参数沙漠与作用域丛林的求生指南

欢迎来到ZyyOvO的博客✨&#xff0c;一个关于探索技术的角落&#xff0c;记录学习的点滴&#x1f4d6;&#xff0c;分享实用的技巧&#x1f6e0;️&#xff0c;偶尔还有一些奇思妙想&#x1f4a1; 本文由ZyyOvO原创✍️&#xff0c;感谢支持❤️&#xff01;请尊重原创&#x1…

MacBook Pro使用FFmpeg捕获摄像头与麦克风推流音视频

FFmpeg查看macos系统音视频设备列表 ffmpeg -f avfoundation -list_devices true -i "" 使用摄像头及麦克风同时推送音频及视频流: ffmpeg -f avfoundation -pixel_format yuyv422 -framerate 30 -i "0:1" -c:v libx264 -preset ultrafast -b:v 1000k -…

42 session反序列化漏洞

参考资料&#xff1a;3. php反序列化从入门到放弃(入门篇) - bmjoker - 博客园 session文件上传漏洞利用原理 当在php.ini中设置session.upload_progress.enabled On的时候&#xff0c;PHP将能够跟踪上传单个文件的上传进度。当上传正在进行时&#xff0c;以及在将与session…

leetcode第77题组合

原题出于leetcode第77题https://leetcode.cn/problems/combinations/ 1.树型结构 2.回溯三部曲 递归函数的参数和返回值 确定终止条件 单层递归逻辑 3.代码 二维数组result 一维数组path void backtracking(n,k,startindex){if(path.sizek){result.append(path);return ;}…

基于html的俄罗斯方块小游戏(附程序)

一、前言 俄罗斯方块&#xff08;Tetris&#xff09;是一款经典的益智游戏&#xff0c;由苏联程序员阿列克谢帕基特诺夫&#xff08;Alexey Pajitnov&#xff09;于1984年开发。这款游戏最初是为减少计算机的恐怖效果而设计的&#xff0c;后来通过盗版传播到全球&#xff0c;成…

openwebUI访问vllm加载deepseek微调过的本地大模型

文章目录 前言一、openwebui安装二、配置openwebui环境三、安装vllm四、启动vllm五、启动openwebui 前言 首先安装vllm&#xff0c;然后加载本地模型&#xff0c;会起一个端口好。 在安装openwebui,去访问这个端口号。下面具体步骤的演示。 一、openwebui安装 rootautodl-co…

机器学习:线性回归,梯度下降,多元线性回归

线性回归模型 (Linear Regression Model) 梯度下降算法 (Gradient Descent Algorithm) 的数学公式 多元线性回归&#xff08;Multiple Linear Regression&#xff09;

加入二极管的NE555 PWM 电路

只用电阻、电容构成的一般定时电路的占空比无法低于50%&#xff0c;如下图&#xff1a; 电容的充电路径上串联了R1 和R2&#xff0c;而放电路径上只有R2&#xff0c;所以放电的时间不可能比充电长。加入二极管就能解决这个问题&#xff0c;用二极管把充电和放电路径分离开&…

游戏引擎学习第131天

仓库:https://gitee.com/mrxiao_com/2d_game_3 运行游戏并识别我们的小问题 今天的工作重点是对游戏引擎进行架构优化&#xff0c;特别是针对渲染和多线程的部分。目前&#xff0c;我们的目标是让地面块在独立线程上进行渲染&#xff0c;以提高性能。在此过程中&#xff0c;我…

并发编程1

JAVA线程回顾 多线程 多个并行的线程来完成个自的任务&#xff0c;优点是程序响应速度更快&#xff0c;程序性能得到提升。 并行执行与并发执行 并发执行就是在单核CPU下&#xff0c;现成实际上是串行执行的&#xff0c;任务调度器将cpu的时间片分给不同的线程使用&#xff0…

AI: Cursor是否已奠定AI开发环境的龙头地位?

近年来&#xff0c;人工智能&#xff08;AI&#xff09;在软件开发领域的应用迅速升温&#xff0c;而Cursor作为一款AI驱动的代码编辑器&#xff0c;凭借其创新功能和市场表现&#xff0c;引发了广泛讨论。许多人认为&#xff0c;Cursor已经奠定了AI开发环境的龙头地位。然而&a…

贪心算法+题目

贪心算法 跳跃游戏跳跃游戏2 跳跃游戏 题目 拿到题目就暴力穷举&#xff0c;我用的是dfs&#xff0c;加上备忘录之后还是超出时间限制。就考虑一下贪心算法。你想 我在[0,n-2]位置遍历求出可以跳跃的最远距离&#xff0c;用farthest更新最大值&#xff0c;如果>终点就返回t…

02 2个交换机+vlan构造两个逻辑上的子网

前言 这是最近一个朋友的 ensp 相关的问题, 这里来大致了解一下 ensp, 计算机网络拓扑 相关基础知识 这里一系列文章, 主要是参照了这位博主的 ensp 专栏 这里 我只是做了一个记录, 自己实际操作了一遍, 增强了一些 自己的理解 当然 这里仅仅是一个 简单的示例, 实际场景…

【前端基础】Day 7 CSS高级技巧

目录 1. 精灵图 1.1 为什么需要精灵图 1.2 精灵图&#xff08;sprites&#xff09;的使用 2. 字体图标 2.1 字体图标的产生 2.2 字体图标的优点 2.3 字体图标的下载 2.4 字体图标的引入 2.5 字体图标的追加 3. CSS三角形 4. CSS用户界面样式 4.1 更改用户鼠标样式 …

React低代码项目:问卷编辑器 II

吐司问卷&#xff1a;问卷编辑器 II Date: February 26, 2025 Log **软件设计的可拓展性&#xff1a;**对修改封闭&#xff0c;对拓展开放 工具栏 删除组件 需求&#xff1a; 要点&#xff1a; 实现删除选中组件 思路&#xff1a;重新计算 selectedId&#xff0c;优先选择…

图像处理之图像边缘检测算法

目录 1 图像边缘检测算法简介 2 Sobel边缘检测 3 经典的Canny边缘检测算法 4 演示Demo 4.1 开发环境 4.2 功能介绍 4.3 下载地址 参考 1 图像边缘检测算法简介 图像边缘检测是计算机视觉和图像处理中的基本问题&#xff0c;主要目的是提取图像中明暗变化明显的边缘细节…

数据结构(初阶)(八)----排序

排序 概念 排序&#xff1a;所谓排序&#xff0c;就是使⼀串记录&#xff0c;按照其中的某个或某些关键字的⼤⼩&#xff0c;递增或递减的排列起来的 操作。 比较排序 插入排序 直接插入排序 直接插⼊排序是⼀种简单的插⼊排序法&#xff0c;其基本思想是&#xff1a;把待…

计算机毕业设计SpringBoot+Vue.js基于JAVA语言的在线考试与学习交流网页平台(源码+文档+PPT+讲解)

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 作者简介&#xff1a;Java领…

聊一聊 IM 如何优化数据库

IM 系列 im doc 实时通讯文档仓库 聊一聊 IM 是什么&#xff1f; IM 即时通讯系统概览 聊一聊 IM 要如何设计&#xff1f; 聊一聊 IM 要如何设计功能模块&#xff1f; 聊一聊 IM 要如何进行架构设计&#xff1f; 聊一聊 IM 要如何进行技术选型&#xff1f; 聊一聊 IM 要…

人工智能AI在汽车设计领域的应用探索

我是穿拖鞋的汉子&#xff0c;魔都中坚持长期主义的汽车电子工程师。 老规矩&#xff0c;分享一段喜欢的文字&#xff0c;避免自己成为高知识低文化的工程师&#xff1a; 简单&#xff0c;单纯&#xff0c;喜欢独处&#xff0c;独来独往&#xff0c;不易合同频过着接地气的生活…