前面的系列我们讲了自定义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/

最新文章

  1. jpa+springmvc+springdata(一)
  2. [LeetCode] Unique Substrings in Wraparound String 封装字符串中的独特子字符串
  3. AndroidStudio开发环境配置-Windows
  4. Nodejs 饭店
  5. Java设计模式-访问者模式(Visitor)
  6. 由于lightdm.conf 错误无法进入ubuntu 的办法
  7. 你不知道的JavaScript(作用域和闭包)
  8. Objective-C Runtime 运行时之三:方法与消息(转载)
  9. (转)Apache与Tomcat 区别联系
  10. 51nod1268 和为K的组合(DFS)
  11. [小程序]_ELVE_小程序开发(1)
  12. python基础(15)-socket网络编程&amp;socketserver
  13. Requests对HTTPS请求验证SSL证书
  14. ASP.NET quartz 定时任务
  15. Idea默认的全局设置,如Maven等
  16. 洛谷.3391.[模板]文艺平衡树(Splay)
  17. ajax中的contendType和dataType知识点梳理
  18. idea maven编译jdk报错
  19. 一个汉字转拼音的php类
  20. win10 WiFi 密码查询 命令

热门文章

  1. 【转】android中如何实现离线缓存
  2. 【转】微信中MMAlert(半透明底部弹出菜单)的使用介绍
  3. NetCore服务虚拟化01(集群组件Sodao.Core.Grpc)
  4. 【大数据之数据仓库】GreenPlum优化器对比测试
  5. web静态资源的访问(笔记)
  6. kali linux之sqlmap
  7. 【bzoj4869】[Shoi2017]相逢是问候 线段树+扩展欧拉定理
  8. mysql 远程访问不行解决方法 Host is not allowed to connect to this MySQL server
  9. 解决tomcat启动 startup.bat的时候一闪而过(就是java环境变量的配置)
  10. C# 注册Dll文件