南京做网站南京乐识最优/安徽seo推广

南京做网站南京乐识最优,安徽seo推广,做网站怎么申请域名,广州网站开发怎么做1.为什么需要 allocator? 在 C 中,动态内存管理通常通过 new 和 delete 完成: int* p new int; // 分配内存 构造对象 delete p; // 析构对象 释放内存 但 new 和 delete 有两个问题: 耦合性:将内…

1.为什么需要 allocator?

在 C++ 中,动态内存管理通常通过 new 和 delete 完成:

int* p = new int;    // 分配内存 + 构造对象
delete p;            // 析构对象 + 释放内存

但 new 和 delete 有两个问题:

  1. 耦合性:将内存分配和对象构造合并为一个操作。

  2. 灵活性不足:无法适配不同的内存管理策略(如内存池、共享内存等)。

allocator 类的核心目标就是解耦内存分配和对象构造,提供更灵活的内存管理。


 2.allocator 的核心作用

std::allocator 是标准库容器(如 vectorlistmap 等)默认使用的内存分配器。它主要有以下作用:

1. 分离内存分配和对象构造
  • 分配内存:先分配原始内存块,但不构造对象。

  • 构造对象:在已分配的内存上手动构造对象。

  • 析构对象:手动析构对象,但不释放内存。

  • 释放内存:最终释放原始内存块。

#include <memory>std::allocator<int> alloc;// 1. 分配内存(未初始化)
int* p = alloc.allocate(5); // 分配 5 个 int 的空间// 2. 构造对象
for (int i = 0; i < 5; ++i) {alloc.construct(p + i, i); // 在 p[i] 处构造 int 对象,值为 i
}// 3. 析构对象
for (int i = 0; i < 5; ++i) {alloc.destroy(p + i);      // 析构 p[i] 处的对象
}// 4. 释放内存
alloc.deallocate(p, 5);
2. 支持自定义内存管理策略

通过自定义 allocator,可以实现:

  • 内存池:预分配大块内存,减少碎片。

  • 共享内存:在进程间共享内存区域。

  • 性能优化:针对特定场景优化内存分配速度。


3.allocator 的典型使用场景

场景 1:标准库容器

所有标准库容器(如 std::vector)默认使用 std::allocator

template <class T, class Allocator = std::allocator<T>>
class vector {
private:T* data_ = nullptr;         // 指向动态数组的指针size_t size_ = 0;          // 当前元素数量size_t capacity_ = 0;      // 当前分配的内存容量Allocator allocator_;      // 内存分配器对象public:// ... 保留已有构造函数 ...// 赋值运算符(拷贝并交换 idiom)vector& operator=(const vector& other) {if (this != &other) {vector temp(other); // 利用拷贝构造函数swap(*this, temp);  // 交换资源}return *this;}// 移动赋值运算符vector& operator=(vector&& other) noexcept {if (this != &other) {clear();allocator_.deallocate(data_, capacity_);data_ = other.data_;size_ = other.size_;capacity_ = other.capacity_;allocator_ = std::move(other.allocator_);other.data_ = nullptr;other.size_ = other.capacity_ = 0;}return *this;}// 交换两个vector(noexcept保证)friend void swap(vector& a, vector& b) noexcept {using std::swap;swap(a.data_, b.data_);swap(a.size_, b.size_);swap(a.capacity_, b.capacity_);swap(a.allocator_, b.allocator_);}// 添加emplace_back支持template <class... Args>void emplace_back(Args&&... args) {if (size_ >= capacity_) {reserve(capacity_ ? capacity_ * 2 : 1);}allocator_.construct(data_ + size_++, std::forward<Args>(args)...);}// 完善reserve的异常安全void reserve(size_t new_cap) {if (new_cap <= capacity_) return;T* new_data = allocator_.allocate(new_cap);size_t i = 0;try {for (; i < size_; ++i) {allocator_.construct(new_data + i, std::move_if_noexcept(data_[i]));allocator_.destroy(data_ + i);}} catch (...) {// 回滚已构造元素for (size_t j = 0; j < i; ++j) {allocator_.destroy(new_data + j);}allocator_.deallocate(new_data, new_cap);throw;}allocator_.deallocate(data_, capacity_);data_ = new_data;capacity_ = new_cap;}// ... 保留其他已有方法 ...
};

要点说明:

1. 使用分配器进行内存管理(allocate/deallocate)
2. 实现RAII原则,在析构函数中释放资源
3. 支持基础操作:push_back/pop_back/clear
4. 包含移动语义优化性能
5. 实现迭代器访问功能
6. 包含简单的扩容策略(容量翻倍)
这个只是简单模仿vector容器的核心机制,实际标准库实现会更复杂(包含异常安全、优化策略等很多东西)

场景 2:自定义内存分配策略

例如,实现一个简单的内存池:

template <typename T>
class MemoryPoolAllocator {
public:// 必需的类型定义(C++标准要求)using value_type = T;               // 分配的元素类型using pointer = T*;                 // 指针类型using const_pointer = const T*;     // 常指针类型using size_type = std::size_t;      // 大小类型using difference_type = std::ptrdiff_t; // 指针差异类型// 分配器传播特性(影响容器拷贝行为)using propagate_on_container_copy_assignment = std::true_type;using propagate_on_container_move_assignment = std::true_type;using propagate_on_container_swap = std::true_type;/*** @brief 默认构造函数(必须支持)* @note 需要保证同类型的不同allocator实例可以互相释放内存*/MemoryPoolAllocator() noexcept = default;/*** @brief 模板拷贝构造函数(必须支持)* @tparam U 模板参数类型* @note 允许从其他模板实例化的allocator进行构造*/template <typename U>MemoryPoolAllocator(const MemoryPoolAllocator<U>&) noexcept {}/*** @brief 内存分配函数(核心接口)* @param n 需要分配的元素数量* @return 指向分配内存的指针* @exception 可能抛出std::bad_alloc或派生异常*/T* allocate(size_t n) {// TODO: 实现内存池分配逻辑// 建议方案:// 1. 计算总字节数 bytes = n * sizeof(T)// 2. 从内存池获取对齐的内存块// 3. 返回转换后的指针return static_cast<T*>(::operator new(n * sizeof(T)));}/*** @brief 内存释放函数(核心接口)* @param p 需要释放的内存指针* @param n 释放的元素数量* @note 必须保证p是通过allocate(n)分配的指针*/void deallocate(T* p, size_t n) noexcept {// TODO: 实现内存池回收逻辑// 建议方案:// 1. 将内存块标记为空闲// 2. 返回内存池供后续重用::operator delete(p);}/*** @brief 分配器比较函数(必须支持)* @note 不同实例是否应该被视为相等,需根据内存池实现决定*/bool operator==(const MemoryPoolAllocator&) const noexcept { return true; // 假设所有实例使用同一内存池}bool operator!=(const MemoryPoolAllocator&) const noexcept {return false;}/*** @brief 可选:对象构造函数(C++20前需要)* @tparam Args 构造参数类型*/template <typename... Args>void construct(T* p, Args&&... args) {::new(static_cast<void*>(p)) T(std::forward<Args>(args)...);}/*** @brief 可选:对象析构函数(C++20前需要)*/void destroy(T* p) {p->~T();}
};
场景 3:避免默认初始化

默认的 new 会调用构造函数,而 allocator 可以先分配内存,再按需构造对象:

std::allocator<std::string> alloc;
std::string* p = alloc.allocate(3); // 仅分配内存,不构造对象// 按需构造
alloc.construct(p, "hello");         // 构造第一个 string
alloc.construct(p + 1, "world");     // 构造第二个 string

4.allocator 的关键接口

以下是 std::allocator 的核心方法:

方法作用
allocate(n)分配 n 个对象的原始内存(未初始化)
deallocate(p, n)释放内存(需先析构所有对象)
construct(p, args)在位置 p 构造对象,参数为 args
destroy(p)析构 p 处的对象

5.自定义 allocator 的要点

5.1. 必须提供的类型别名

自定义 allocator 需要定义以下类型:

template <typename T>
class CustomAllocator {
public:using value_type = T; // 必须定义// 其他必要类型...
};
5.2. 实现必要接口

至少需要实现 allocate 和 deallocate 方法:

T* allocate(size_t n) {return static_cast<T*>(::operator new(n * sizeof(T)));
}void deallocate(T* p, size_t n) {::operator delete(p);
}
5.3. 支持 rebind 机制

容器可能需要分配其他类型的对象(如链表节点的分配器):

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

6.C++17 后的改进

C++17 引入了 std::allocator_traits,简化了自定义 allocator 的实现。即使自定义分配器未实现某些接口,allocator_traits 会提供默认实现:

template <typename Alloc>
using allocator_traits = std::allocator_traits<Alloc>;// 使用示例
auto p = allocator_traits<Alloc>::allocate(alloc, n);

7.总结

  • 核心作用:解耦内存分配与对象构造,提供更灵活的内存管理。

  • 默认行为:标准库容器使用 std::allocator

  • 自定义场景:内存池、性能优化、特殊内存区域(如共享内存)。

  • 关键接口allocatedeallocateconstructdestroy

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Headless Chrome 优化:减少内存占用与提速技巧

在当今数据驱动的时代&#xff0c;爬虫技术在各行各业扮演着重要角色。传统的爬虫方法往往因为界面渲染和资源消耗过高而无法满足大规模数据采集的需求。本文将深度剖析 Headless Chrome 的优化方案&#xff0c;重点探讨如何利用代理 IP、Cookie 和 User-Agent 设置实现内存占用…

英伟达GB300新宠:新型LPDDR5X SOCAMM内存

随着人工智能&#xff08;AI&#xff09;、机器学习&#xff08;ML&#xff09;和高性能计算&#xff08;HPC&#xff09;应用的快速发展&#xff0c;对于高效能、大容量且低延迟内存的需求日益增长。NVIDIA在其GB系列GPU中引入了不同的内存模块设计&#xff0c;以满足这些严格…

静态网页应用开发环境搭建实战教程

1. 前言 静态网页开发是前端工程师的基础技能之一&#xff0c;无论是个人博客、企业官网还是简单的Web应用&#xff0c;都离不开HTML、CSS和JavaScript。搭建一个高效的开发环境&#xff0c;能够极大提升开发效率&#xff0c;减少重复工作&#xff0c;并优化调试体验。 本教程…

游戏引擎学习第187天

看起来观众解决了上次的bug 昨天遇到了一个相对困难的bug&#xff0c;可以说它相当棘手。刚开始的时候&#xff0c;没有立刻想到什么合适的解决办法&#xff0c;所以今天得从头开始&#xff0c;逐步验证之前的假设&#xff0c;收集足够的信息&#xff0c;逐一排查可能的原因&a…

对内核fork进程中写时复制的理解记录

前言 文章写于学习Redis时对aof后台重写中写时复制的疑问 一、感到不理解的歧义 在部分技术文档中&#xff08;以小林的文章为例&#xff09;&#xff0c;对写时复制后的内存权限存在如歧义&#xff1a; ! 二、正确技术表述 根据Linux内核实现&#xff08;5.15版本&#x…

Ditto-Talkinghead:阿里巴巴数字人技术新突破 [特殊字符]️

Ditto-Talkinghead&#xff1a;阿里巴巴数字人技术新突破 &#x1f5e3;️ 阿里巴巴推出了一项新的数字人技术&#xff0c;名为 Ditto-Talkinghead。这项技术主要用于生成由音频驱动的说话头&#xff0c;也就是我们常说的“数字人”。不过&#xff0c;现有的基于扩散模型的同类…

每日一题 MySQL基础知识----(三)

数据库常用基础知识&#xff1a;代码讲解和实验 1.创建数据库student 02&#xff0c;创建一个名为student02的数据库 CREATE DATABASE student02; 2.在student02中创建一张 students表&#xff0c;并且具有学生的编号id&#xff0c;姓名name&#xff0c;年龄age&#xff0c;生…

MySQL多表查询实验

1.数据准备 -- 以下语句用于创建 students 表&#xff0c;该表存储学生的基本信息 -- 定义表名为 students CREATE TABLE students (-- 定义学生的唯一标识符&#xff0c;类型为整数&#xff0c;作为主键&#xff0c;且支持自动递增student_id INT PRIMARY KEY AUTO_INCREMENT…

windows第二十章 单文档应用程序

文章目录 单文档定义新建一个单文档应用程序单文档应用程序组成&#xff1a;APP应用程序类框架类&#xff08;窗口类&#xff09;视图类&#xff08;窗口类&#xff0c;属于框架的子窗口&#xff09;文档类&#xff08;对数据进行保存读取操作&#xff09; 直接用向导创建单文档…

第一天 Linux驱动程序简介

目录 一、驱动的作用 二、裸机驱动 VS linux驱动 1、裸机驱动 2、linux驱动 三、linux驱动位于哪里&#xff1f; 四、应用编程 VS 内核编程 1、共同点 2、不同点 五、linux驱动分类 1、字符设备 2、块设备 3、网络设备 六、Linux驱动学习难点与误区 1、学习难点 …

PaddleX产线集成功能的使用整理

一、环境搭建 1.1 安装paddle-gpu 需要根据安装机器的cuda的版本&#xff0c;选择合适的版本进行安装 #安装paddle-gpu 官网链接 https://www.paddlepaddle.org.cn/install/quick?docurl/documentation/docs/zh/install/pip/linux-pip.html python -m pip install paddle…

docker-compese 启动mysql8.0.36与phpmyadmin,并使用web连接数据库

1、找一个文件夹&#xff0c;比如 E:\zqy\file\mysql&#xff0c;cd到这个目录下创建文件docker-compose.yml 2、将下面的代码块复制到docker-compose.yml文件中 version: 3.3 services:mysql:image: mysql:8.0.36container_name: mysqlrestart: alwaysports:- 3306:3306netw…

mcp 接freecad画齿轮

from mcp.server.fastmcp import FastMCP import freecad.gears.commands import os from freecad import app from freecad import part mcp FastMCP("Demo")mcp.tool() def create_gear(num_teeth20,height10,double_helix True):"""创建一个渐开线…

【大前端系列19】JavaScript核心:Promise异步编程与async/await实践

JavaScript核心&#xff1a;Promise异步编程与async/await实践 系列: 「全栈进化&#xff1a;大前端开发完全指南」系列第19篇 核心: 深入理解Promise机制与async/await语法&#xff0c;掌握现代异步编程技术 &#x1f4cc; 引言 在JavaScript的世界中&#xff0c;异步编程是无…

测试:认识Bug

目录 一、软件测试的生命周期 二、bug 一、软件测试的生命周期 软件测试贯穿于软件的生命周期。 需求分析&#xff1a; ⽤⼾⻆度&#xff1a;软件需求是否合理 技术⻆度&#xff1a;技术上是否可⾏&#xff0c;是否还有优化空间 测试⻆度&#xff1a;是否存在业务逻辑错误、…

综合实验2

1、sw1和sw2之间互为备份 [sw1]interface Eth-Trunk 0 &#xff08;创建聚合接口&#xff09; [sw1-Eth-Trunk0]trunkport g0/0/1 &#xff08;将物理接口划入到聚合接口中&#xff09; [sw1-Eth-Trunk0]trunkport g0/0/2 [sw2]interface Eth-Trunk 0 [sw2-Eth-T…

【ArcGIS】ArcGIS10.6彻底卸载和ArcGIS10.2安装全过程

卸载python3后,解决了ArcGIS与python3冲突问题后,软件可以正常打开使用了 但是还是出现了问题 用ArcGIS 进行空间分析时,中间操作没有任何报错和问题,但是就是没有运行结果 在别人的软件上操作一遍可以出现运行结果 关闭确有这个,但真的不是我给它的运行时间不够,反反复复试…

Qwen-0.5b linux部署

参考链接 https://blog.csdn.net/imwaters/article/details/145489543 https://modelscope.cn/models/modelscope/ollama-linux 1. ollama安装 # 安装ModelScope工具包&#xff0c;用于下载和管理AI模型 pip install modelscope# 下载Ollama的Linux版本安装包 # --model 指定…

【深度学习】GAN生成对抗网络:原理、应用与发展

GAN生成对抗网络&#xff1a;原理、应用与发展 文章目录 GAN生成对抗网络&#xff1a;原理、应用与发展1. 引言2. GAN的基本原理2.1 核心思想2.2 数学表达2.3 训练过程 3. GAN的主要变体3.1 DCGAN (Deep Convolutional GAN)3.2 CGAN (Conditional GAN)3.3 CycleGAN3.4 StyleGAN…

【新人系列】Golang 入门(八):defer 详解 - 上

✍ 个人博客&#xff1a;https://blog.csdn.net/Newin2020?typeblog &#x1f4dd; 专栏地址&#xff1a;https://blog.csdn.net/newin2020/category_12898955.html &#x1f4e3; 专栏定位&#xff1a;为 0 基础刚入门 Golang 的小伙伴提供详细的讲解&#xff0c;也欢迎大佬们…