前面的系列我们讲了自定义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# Socket通信改进记录

    1. Socket 使用原始Socket,Send和Recv方法 进行发送和消息获取.(另起后台线程 不停获取和发送) public void RecvMsg() { //receive messag ...

  2. Ubuntu16.04修改静态ip地址

    https://blog.csdn.net/mdw5521/article/details/79270035

  3. sed 增删改查详解以及 sed -i原理

    我为什么要详细记录sed命令:     sed 擅长取行.工作中三剑客使用频率最高,本篇文章将对sed命令常用的 增,删,改,查 进行详细讲解,以备以后工作中遗忘了查询,sed命令是作为运维人员来说, ...

  4. Docker 的部署方式

    在使用 docker run 命令启动 Docker 容器时,如果需要进行端口映射.目录挂载.网络信息等配置,整条命令将变得非常长,并且由于是一条 shell 命令,修改和复用也不方便.我们在大规模部 ...

  5. 「CF622F」The Sum of the k-th Powers「拉格朗日插值」

    题意 求\(\sum_{i=1}^n i^k\),\(n \leq 10^9,k \leq 10^6\) 题解 观察可得答案是一个\(k+1\)次多项式,我们找\(k+2\)个值带进去然后拉格朗日插值 ...

  6. docker容器管理及网络管理

    防火墙规则—— INPUT 主要用于主机防火墙,设置规则屏蔽处理进入本机的数据包示例:禁止10.180.100.141这个机器访问我本机的web服务iptables -t filter -A INPU ...

  7. 深度学习之 TensorFlow(五):mnist 的 Alexnet 实现

    尝试用 Alexnet 来构建一个网络模型,并使用 mnist 数据查看训练结果. 我们将代码实现分为三个过程,加载数据.定义网络模型.训练数据和评估模型. 实现代码如下: #-*- coding:u ...

  8. numpy常用功能总结、python格式化输入输出

    #coding:utf-8 #author:徐卜灵 ##################### #由于在各大公司笔试的时候总是会遇到一些格式化输入输出数据,今天就来总结一下. #结合numpy来处理数 ...

  9. Resurrectio-capserjs的自动化脚本录制工具

    [根据github上的文档说明整理] Phantom下的任何操作都可以录制 Resurrectio是一个Chrome插件,他可以记录浏览器的操作,并转化成对应的casperjs脚本 Resurrect ...

  10. 14、OpenCV Python 直线检测

    __author__ = "WSX" import cv2 as cv import numpy as np #-----------------霍夫变换------------- ...