前面的系列我们讲了自定义new和delete操作,其中针对deleteArray的问题还有需要优化的地方。我们这次就针对POD类型进行一次优化。

下面的代码是针对POD类型的模板函数实现,分别为NewArrayPOD和DeleteArrayPOD:

template <typename T, class ARENA>
T* NewArrayPOD(ARENA& arena, size_t N, const char* file, int line)
{
return static_cast(arena.Allocate(sizeof(T)*N, file, line));
} template <typename T, class ARENA>
void DeleteArrayPOD(T* ptr, ARENA& arena)
{
arena.Free(ptr);
}

从上面可以看出,针对POD类型,我们不需要调用析构函数,只需要将内存释放即可,所以其区别于非POD类型。但是如果实现了POD和非POD两个版本的函数,该如何让我们的宏根据类型自己调用合适的函数呢?

我们采用的方式是放弃NewArrayPOD和DeleteArrayPOD这种另外实现一个函数的方式,而是重载NewArray和DeleteArray函数,使宏根据参数来正确调用对应的函数。我们首先要实现的是一个traits-class,它用来判断一个类型是不是POD类型。这可以通过定义一个基础模板类和一些特化版本来实现,代码如下:

template <typename T>
struct IsPOD
{
static const bool Value = false;
}; template <>
struct IsPOD<char>
{
static const bool Value = true;
}; template <>
struct IsPOD<int>
{
static const bool Value = true;
}; // etc.

对于任何一个给定的类型T,我们可以通过编译期常量IsPOD<T>::value来确定T是否为一个POD类型。当然了,如果使用了C++11及以后的标准,标准库中就实现了std::is_pod。

两个重载版本的函数实现如下:

template <typename T, class ARENA>
T* NewArray(ARENA& arena, size_t N, const char* file, int line, NonPODType)
{
// implementation for non-POD types
} template <typename T, class ARENA>
T* NewArray(ARENA& arena, size_t N, const char* file, int line, PODType)
{
// implementation for POD types
} template <typename T, class ARENA>
void DeleteArray(T* ptr, ARENA& arena, NonPODType)
{
// implementation for non-POD types
} template <typename T, class ARENA>
void DeleteArray(T* ptr, ARENA& arena, PODType)
{
// implementation for POD types
}

当然了,看到上面的代码后,你可能会问,C++的重载是根据类型来的,又不是根据值,我们不能只通过一个true和一个false来重载函数。所以为了让上面的代码能够正确工作,我们需要再实现一个模板黑魔法称为type-based dispatching。

template <bool I>
struct IntToType
{
}; typedef IntToType<false> NonPODType;
typedef IntToType<true> PODType;

这样,我们就可以将上一节中的宏定义修改为:

// old version
#define ME_NEW_ARRAY(type, arena) NewArray<TypeAndCount<type>::Type>(arena, TypeAndCount<type>::Count, __FILE__, __LINE__) // new version
#define ME_NEW_ARRAY(type, arena) NewArray<TypeAndCount<type>::Type>(arena, TypeAndCount<type>::Count, __FILE__, __LINE__, IntToType<IsPOD<TypeAndCount<type>::Type>::Value>())

有点小长,但是如果理解了背后的技巧和原理,实现起来其实并不复杂。但是我们还有最后一个问题,就是在宏定义#define OM_DELETE_ARRAY(object, arena) DeleteArray(object, arena)中不能直接使用Is_POD<T>方法,因为obejct本身是一个值,不是一个一个类型,我们又不想显式的再用一个参数来制定类型,因为编译器已经知道了类型,所以我们要做的就是让编译器自己推到出类型再调用DeleteArray函数,所以我们只需将DeleteArray函数封装在一个模板函数中,就可以实现这一点,代码如下:

template <typename T, class ARENA>
void DeleteArray(T* ptr, ARENA& arena)
{
DeleteArray(ptr, arena, IntToType<IsPOD<T>::Value>());
}

至此为止,我们对POD和非POD类型的优化工作已经结束,现在我们可以高效的使用自定义的OM_NEW_ARRAY和OM_DELETE_ARRAY了。

参考link:

https://stoyannk.wordpress.com/2018/01/10/generic-memory-allocator-for-c-part-3/

https://bitsquid.blogspot.com/2010/09/custom-memory-allocation-in-c.html

https://blog.molecular-matters.com/

C++ Memory System Part3 : 优化的更多相关文章

  1. 内存泄漏 Memory Leaks 内存优化 MD

    Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...

  2. gem5: 使用ruby memory system中的mesh结构 出现AssertionError错误

    问题:在使用ruby memory system中的mesh结构測试时,出现例如以下错误: Traceback (most recent call last): File "<stri ...

  3. PatentTips - Mechanisms for strong atomicity in a transactional memory system

    BACKGROUND Advances in semi-conductor processing and logic design have permitted an increase in the ...

  4. Bit error testing and training in double data rate (ddr) memory system

    DDR PHY interface bit error testing and training is provided for Double Data Rate memory systems. An ...

  5. Power management in semiconductor memory system

    A method for operating a memory module device. The method can include transferring a chip select, co ...

  6. armv8 memory system

    在armv8中,由于processor的预取,流水线, 以及多线程并行的执行方式,而且armv8-a中,使用的是一种weakly-ordered memory model, 不保证program or ...

  7. C++ Memory System Part2: 自定义new和delete

    在第一部分中,我们介绍了new / delete的具体用法和背后的实现细节,这次我们将构建我们自己的小型工具集,可以使用我们自定义的allocator类来创建任意类型的实例(或者实例数组),我们需要做 ...

  8. 雪花算法对System.currentTimeMillis()优化真的有用么?

    前面已经讲过了雪花算法,里面使用了System.currentTimeMillis()获取时间,有一种说法是认为System.currentTimeMillis()慢,是因为每次调用都会去跟系统打一次 ...

  9. C++ Memory System Part1: new和delete

    在深入探索自定义内存系统之前,我们需要了解一些基础的背景知识,这些知识点是我们接下来自定义内存系统的基础.所以第一部分,让我们来一起深入了解一下C++的new和delete家族,这其中有很多令人吃惊的 ...

随机推荐

  1. C#中base的作用

    using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threa ...

  2. 函数形参为基类数组,实参为继承类数组,下存在的问题------c++程序设计原理与实践(进阶篇)

    示例: #include<iostream> using namespace std; class A { public: int a; int b; A(int aa=1, int bb ...

  3. 笔记本小键盘提示 C#

    穷人家的孩子,买了个笔记本愣是没有小键盘提示灯. 牛的是人家给了一个大写提示灯. 更牛的是他妈给了音量关闭打开的提示灯,还他妈是橙色的!!!!!! 没办法 弄了小程序 来判断是否打开小键盘了. 本来是 ...

  4. jstack应用-查找CPU飚高的原因

    场景 在系统上线后,经常会遇到运维的同学跑过来说:“这次发版后,cpu线程使用率到一场,到100%了”.这时候不要慌,可以使用堆转储来分析到底是哪个线程引起的. 查找元凶 发现pid=17850的进程 ...

  5. Maven配置与安装

    最近重装了一下系统,便重新安装与配置了maven,记录这个过程并分享出来. 注意:maven安装需要Java依赖,我这里使用的是jdk1.8. 1.安装并配置环境变量 首先在 maven 官网下载 m ...

  6. application的使用(实现计数器)

    application在整个WEB项目中共享使用数据. 常用方法: getAttribute(); setAttribute();示列: <%    Object count=applicati ...

  7. 图解SQL Server 2008入门必会

    图解SQL Server 2008入门必会   https://jingyan.baidu.com/article/656db918eded1ee381249c0b.html 图解SQL Server ...

  8. Hibernate学习笔记(六)—— 查询优化

    一.Hibernate的抓取策略 1.1 什么是抓取策略 抓取策略是当应用程序需要在(Hibernate实体对象图的)关联关系间进行导航的时候,Hibernate如何获取关联对象的策略. HIbern ...

  9. ES6,CommonJS 区别

    Javascript,javascript是一种脚本编程语言,有自己独立的语法与语义,没有javascript,也就没有其他的那些概念了. 关于ES6,可直接理解为javascript的增强版(增加了 ...

  10. 洛谷P2146 [NOI2015]软件包管理器

    https://www.luogu.org/problemnew/show/P2146 传送门 简单的树链剖分......维护下当前安装了多少个包......修改后查询下就行了......附上极其丑陋 ...