C++学习(2):分配器allocator

new和operator new

new是关键字,new 操作符的执行过程:

  1. 调用operator new分配内存;
  2. 调用构造函数在operator new返回的内存地址处生成类对象;

operator new是一个函数,可以被重载,通过重载它,可以改变new操作符的功能。功能类似malloc,如果类中没有重载operator new,那么调用的就是全局的::operator new来从堆中分配内存。

new将内存分配和对象构造组合在一起。
一般情况下,将内存分配和对象构造组合在一起会导致不必要的浪费。可能创建了一些永远不会用到的对象,或者使用到的元素被重复赋值两次。
allocator类帮助我们将内存分配和对象构造分离,可以分配大量内存,只有在真正需要的时候才执行对象创建操作。

类模板allocator

继承自__allocator_base,只定义了构造和析构函数。

template<typename _Tp>class allocator: public __allocator_base<_Tp>{public:typedef size_t     size_type;typedef ptrdiff_t  difference_type;typedef _Tp*       pointer;typedef const _Tp* const_pointer;typedef _Tp&       reference;typedef const _Tp& const_reference;typedef _Tp        value_type;template<typename _Tp1>struct rebind{ typedef allocator<_Tp1> other; };#if __cplusplus >= 201103L// _GLIBCXX_RESOLVE_LIB_DEFECTS// 2103. std::allocator propagate_on_container_move_assignmenttypedef true_type propagate_on_container_move_assignment;typedef true_type is_always_equal;
#endifallocator() throw() { }allocator(const allocator& __a) throw()//throw()表示该函数不会抛出异常: __allocator_base<_Tp>(__a) { }template<typename _Tp1>allocator(const allocator<_Tp1>&) throw() { }~allocator() throw() { }// Inherit everything else.};

__allocator_base是__gnu_cxx::new_allocator<_Tp>别名

 template<typename _Tp>using __allocator_base = __gnu_cxx::new_allocator<_Tp>;

类模板new_allocator

除了析构函数和构造函数之外,还定义了allocate、deallocate分配和释放内存、construct、destroy构造和析构对象。

template<typename _Tp>class new_allocator{public:typedef size_t     size_type;typedef ptrdiff_t  difference_type;typedef _Tp*       pointer;typedef const _Tp* const_pointer;typedef _Tp&       reference;typedef const _Tp& const_reference;typedef _Tp        value_type;template<typename _Tp1>struct rebind{ typedef new_allocator<_Tp1> other; };#if __cplusplus >= 201103L// _GLIBCXX_RESOLVE_LIB_DEFECTS// 2103. propagate_on_container_move_assignmenttypedef std::true_type propagate_on_container_move_assignment;
#endifnew_allocator() _GLIBCXX_USE_NOEXCEPT { }new_allocator(const new_allocator&) _GLIBCXX_USE_NOEXCEPT { }template<typename _Tp1>new_allocator(const new_allocator<_Tp1>&) _GLIBCXX_USE_NOEXCEPT { }~new_allocator() _GLIBCXX_USE_NOEXCEPT { }pointer address(reference __x) const _GLIBCXX_NOEXCEPT{ return std::__addressof(__x); }const_pointer address(const_reference __x) const _GLIBCXX_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.pointer allocate(size_type __n, const void* = static_cast<const void*>(0)){if (__n > this->max_size())std::__throw_bad_alloc();return static_cast<_Tp*>(::operator new(__n * sizeof(_Tp)));}// __p is not permitted to be a null pointer.void deallocate(pointer __p, size_type){::operator delete(__p);}size_type max_size() const _GLIBCXX_USE_NOEXCEPT{ return size_t(-1) / sizeof(_Tp); }template<typename _Up, typename... _Args>void construct(_Up* __p, _Args&&... __args){ ::new((void *)__p) _Up(std::forward<_Args>(__args)...); }template<typename _Up>void destroy(_Up* __p) { __p->~_Up(); }};

可以看到,在allocate和deallocate中分别调用了::operator new和::operator delete,实现分配和释放内存。::运算符被称为作用域解析运算符,通过加上这个前缀,告诉编译器在全局命名空间中查找该类型。

pointer allocate(size_type __n, const void* = static_cast<const void*>(0))
{if (__n > this->max_size())std::__throw_bad_alloc();return static_cast<_Tp*>(::operator new(__n * sizeof(_Tp)));
}
// __p is not permitted to be a null pointer.
void deallocate(pointer __p, size_type)
{::operator delete(__p);
}

在construct()调用了构造函数,使用placement new在指定内存中构建对象(定位new允许我们在一个特定的、预先分配的内存地址上构造对象,placement new是一种特殊的operate new),并使用std::forward转发模板参数到构造函数。

template<typename _Up, typename... _Args>void construct(_Up* __p, _Args&&... __args){ ::new((void *)__p) _Up(std::forward<_Args>(__args)...); }

在destroy()中调用了析构函数。

template<typename _Up>void destroy(_Up* __p) { __p->~_Up(); }

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

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

相关文章

微服务开发中,使用AOP和自定义注解实现对权限的校验

一、背景 微服务开发中&#xff0c;暴露在外网的接口&#xff0c;为了访问的安全&#xff0c;都是需要在http请求中传入登录时颁发的token。这时候&#xff0c;我们需要有专门用来做校验token并解析用户信息的服务。如下图所示&#xff0c;http请求先经过api网关&#xff0c;网…

[点云分割] 欧式距离分割

效果&#xff1a; 代码&#xff1a; #include <iostream> #include <chrono>#include <pcl/ModelCoefficients.h> // 模型系数的定义 #include <pcl/io/pcd_io.h> #include <pcl/point_types.h> // 各种点云数据类型 #include <pcl/sample_c…

java“贪吃蛇”小游戏

基于java实现贪吃蛇小游戏&#xff0c;主要通过绘制不同的图片并以一定速度一帧一帧地在窗体上进行展示。 我是在javaSwing项目下创建了一个包 名字叫做&#xff1a;Snakes包 包下有一个启动类和一个设置代码的主界面两个类 代码主界面&#xff1a; 代码主界面主要讲解的是 …

window文件夹下python脚本实现批量删除无法预览的图片

你是否遇到过下载的图片会发现有些图片会无法预览情况&#xff1f; 有几种原因可能导致一些图片在预览时无法正常显示&#xff1a; 损坏的图片文件&#xff1a; 图片文件可能损坏或者部分损坏&#xff0c;导致无法被正常解析和预览。这种情况可能是因为文件在传输过程中损坏、…

蓝桥等考C++组别八级003

第一部分:选择题 1、C++ L8 (15分) 整数16,20的最大公约数(公因数)是( )。 A. 1 B. 2 C. 4 D. 80 正确答案:C

机器学习入门(第二天)——感知机

概述 每个算法都是为了解决一类问题&#xff0c;或者说解决之前的问题所创造出来的&#xff0c;而感知机&#xff0c;在解决一类问题的时候也暴露了很多问题&#xff0c;变相的推动了以后的算法的改进方向。 知识树 苹果表示相对重要的 直观介绍 现在有一盘红豆和绿豆&#…

Caused by: java.lang.NoClassDefFoundError: org/mybatis/logging/LoggerFactory

今天项目启动时报错&#xff0c;刻意记录一下&#xff0c;具体报错部分日志如下&#xff1a; Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name sqlSessionFactory defined in class path resource [com/baomidou/mybatis…

2014年8月20日 Go生态洞察:Go在OSCON的精彩亮相

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; &#x1f433; 《面试题大全专栏》 &#x1f995; 文章图文…

使用Vue.js编写页面组件的简单步骤

Vue.js是一个流行的JavaScript框架&#xff0c;用于构建交互式的用户界面。通过Vue&#xff0c;你可以轻松地构建单页面应用&#xff08;SPA&#xff09;并管理页面上的组件。在本篇博文中&#xff0c;我们将介绍如何使用Vue.js编写一个简单的页面组件。 步骤 1: 引入 Vue.js …

Redis+整合SpringDataRedis

Nosql和缓存的背景 数据库架构设计的发展史 第一阶段&#xff1a;单库&#xff1a;随着访问量的增加出现了性能问题 第二阶段&#xff1a;缓存&#xff1a;通过缓存&#xff0c;缓解数据库的压力&#xff0c;优化数据结构和索引 第三阶段&#xff1a;读写分离&#xff1a;数据…

分割list 批量插入数据指定条数数据

一、代码层面切割好list&#xff0c;然后插入 // package org.apache.commons.collections4; 先将list切成1000条一份 List<List<DeptDO>> p1 ListUtils.partition(deptList, 1000); for (List<DeptDO> deptDOS : p1) { // 1000条一次批量插入systemDeptMa…

c# 逆变 / 协变

个人理解&#xff1a; 1. 逆变in向上兼容类 2. 协变out向下兼容类 在面向对象编程中&#xff0c;尤其是使用泛型时&#xff0c;in和out关键字用于限制类型参数的协变性和逆变性。 in关键字&#xff08;逆变&#xff09;&#xff1a; in关键字用于标记泛型类型参数的逆变性。…

Vue History模式的Nginx配置

前言 vue-router有两种模式&#xff0c;hash模式和history模式。直观区别&#xff1a;hash模式url带#号&#xff0c;history模式不带#号。hash模式&#xff1a;由于hash值变化不会导致游览器向服务器发出请求&#xff0c;所以可以实现前端路由&#xff0c;无需额外的配置。his…

网络异常检测

随着社交网络、视频流、点对点技术、云计算和 SaaS 的出现&#xff0c;可以肯定地说&#xff0c;现代企业的好坏取决于他们的网络&#xff0c;尤其是在它们提供的带宽和安全性方面。无论是银行保护其数据免遭盗窃&#xff0c;还是商业组织保护其网络免受安全威胁和攻击&#xf…

XSLVGL2.0 User Manual 系统管理器(v2.0)

XSLVGL2.0 开发手册 XSLVGL2.0 User Manual 系统管理器 1、概述2、特性3、APIs3.1、xs_system_port_get3.2、xs_system_port_flush3.3、xs_system_factory_reset3.4、xs_system_reboot3.5、xs_system_standby3.6、xs_system_standby_wakeup3.7、xs_system_shutdown3.8、xs_sys…

ChatGLM-6B下载安装

ChatGLM-6B下载安装 项目指向 想把模型下载本地微调 通过官网指引需要先下载git-lfs #Linux 下载安装 curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | sudo bash sudo apt-get install git-lfs git lfs install如果是docker中的虚拟机…

如何隐藏自己的代码(很酷)

1.引入 幻想当我们成为一名优秀的程序员&#xff0c;有着各大公司想要买我们的代码&#xff0c;但我们并不想要让他们知道我们代码的实现&#xff0c;毕竟一复制便可以解决&#xff0c;这里我们希望有一种方法可以把我们的核心代码给隐藏掉&#xff0c;那我们又应该怎么去实现呢…

官宣!代理IP品牌「一连IP」正式上线

&#x1f482; 个人网站:【 海拥】【神级代码资源网站】【办公神器】&#x1f91f; 基于Web端打造的&#xff1a;&#x1f449;轻量化工具创作平台&#x1f485; 想寻找共同学习交流的小伙伴&#xff0c;请点击【全栈技术交流群】 今天&#xff0c;企业级代理IP供应商【一连IP】…

通过AX6000路由器,实现外部访问内网的任意主机

概述 这里遇到一个场景,就是需要外部的人员,访问我内网的一台设备,进行内外部的设备联调。 这也是实际环境中,很常见的一种场景。 之前的做法是子设备上运行edge节点,可以直接访问。 但有的设备无法运行edge节点,那么可以参考一下这个方案来实现。 此方案可以摒弃了…

系列九、Entry的key为什么要设计成弱引用

一、Entry的key为什么要设计成弱引用 1.1、四大引用类型 Java中的四种引用 1.2、Entry源码 1.3、为什么设计为弱引用 1.3.1、官网 To help deal with very large and long-lived usages, the hash table entries use WeakReferences for keys。 1.3.2、ThreadLocal引用示意…