在阅读frameworks/rs/cpp/util/RefBase.h之LightRefBase时,我记得《C++设计新思维》里对这种用法是有过介绍的,可是今天翻箱倒柜,怎么都找不到那本奇书了。当年所谓的前卫,今天已经遍地开花,赶紧再把CRTP给复习一下。

CRTP模式主要有两种使用场景:

  • 一、Meyers Counting
template <typename T>
class Counting
{
public:
Counting() { mCount++; }
~Counting() { mCount--; }
static int mCount;
}; template <typename T> int Counting<T>::mCount = ; class CountedA : public Counting<CountedA>{};
class CountedB : public Counting<CountedB>{};

CountedA类和CountedB类都具备了引用计数功能,这是从Counting基类派生下来的,但是引用计数具体的数值是每个子类各自维护,这主要是拜mCount的static属性所赐,Counting<CountedA>和Counting<CountedB>是不同的类,也就有不同的静态成员。

不过LightRefBase显然不是这种应用场景。

  • 二、用编译时绑定替代运行时绑定,避免虚表的时空性能开销。
#include "stdafx.h"
#include <stdio.h> template <typename T>
class Fucker
{
public:
void doFuck() { printf("Failed :(\n"); }
void Fuck() { ((T*)this)->doFuck(); }
}; class AFucker : public Fucker<AFucker>
{}; class BFucker : public Fucker<BFucker>
{
public:
void doFuck() { printf("Shuang :)\n"); }
}; int main(int argc, char** argv)
{
Fucker<BFucker>* pFucker = new BFucker();
pFucker->Fuck();
return ;
}

上面,Fuck()和doFuck()共同完成了虚函数的表演,但无需承担虚表的开销。乍一看LightRefBase也不是这种设计,因为它显然没有虚函数的桥段。

 template <class T>
class LightRefBase
{
public:
inline LightRefBase() : mCount() { }
inline void incStrong(__attribute__((unused)) const void* id) const {
__sync_fetch_and_add(&mCount, );
}
inline void decStrong(__attribute__((unused)) const void* id) const {
if (__sync_fetch_and_sub(&mCount, ) == ) {
delete static_cast<const T*>(this);
}
}
//! DEBUGGING ONLY: Get current strong ref count.
inline int32_t getStrongCount() const {
return mCount;
} typedef LightRefBase<T> basetype; protected:
inline ~LightRefBase() { } private:
friend class ReferenceMover;
inline static void moveReferences(void*, void const*, size_t,
const ReferenceConverterBase&) { } private:
mutable volatile int32_t mCount;
};

它唯一使用了模板参数的地方就是#11,可以断定此处就是该设计的初衷。如果用派生的方式,也可以完成这个任务:

 class Base
{
public:
Base() :mCount() {}
int IncRef() { return ++mCount; }
int DecRef() {
if (--mCount <= ) {
delete this;
}
return mCount;
}
virtual ~Base() {}
private:
int mCount;
}; class Derived : public Base
{};

可这样一来就要引入虚表了——有一个析构虚函数。为什么必须要有它呢?因为Base要用于派生。《Effective C++》第14条曰:总让base class拥有virtual destructor,因为经由基类指针删除子类对象时,基类如果没有虚析构函数,结果将是未定义。于是定义虚析构函数,于是引入虚表。LightRefBase对象的开销本来只有一个int32_t那么大,引入虚表,空间开销就double啦,大大得不划算。因此采用了CRTP模式,算是场景二的变种。

关于CRTP(Curiously Recurring Template Prattern)的使用的更多相关文章

  1. C++ Curiously Recurring Template Prattern(CRTP)例程

    简单介绍和例子请参考:C++ 惯用法 CRTP 简介 下面例子为兼顾CRTP和多态的例子. #include <iostream> #include <vector> usin ...

  2. 用CRTP在C++中实现静态函数的多态

    我上一篇博客[C++的静态分发(CRTP)和动态分发(虚函数多态)的比较](http://www.cnblogs.com/fresky/p/3504241.html)介绍了如何用CRTP(Curiou ...

  3. Java基础常见英语词汇

    Java基础常见英语词汇(共70个) ['ɔbdʒekt] ['ɔ:rientid]导向的                             ['prəʊɡræmɪŋ]编程 OO: object ...

  4. computer English

    算法常用术语中英对照Data Structures 基本数据结构Dictionaries 字典PriorityQueues 堆Graph Data Structures 图Set Data Struc ...

  5. runnable:在线IDE+代码片段分享

    在我之前的博客20个最好的在线IDE中列举过很多在线IDE,可以很方便的在云端执行代码,这样在你手头没有编译器时想试个小程序会非常有用. 今天介绍的这个网站runnable把在线IDE和代码片段结合了 ...

  6. 看到了必须要Mark啊,最全的编程中英文词汇对照汇总(里面有好几个版本的,每个版本从a到d的顺序排列)

    java:  第一章: JDK(Java Development Kit) java开发工具包 JVM(Java Virtual Machine) java虚拟机 Javac  编译命令 java   ...

  7. 当noncopyable遇见singleton

    在实现单例类时,通常要把构造相关的几个函数访问权限设为private或protected(最好是private).但假设一个大型系统中,有数十个单例类(这很正常,单例类其实是外观模式的一种最常用设计) ...

  8. 专业英语词汇(Java)

    abstract (关键字)             抽象 ['.bstr.kt] access                            vt.访问,存取 ['.kses]‘(n.入口, ...

  9. C++ 单例模式总结与剖析

    目录 C++ 单例模式总结与剖析 一.什么是单例 二.C++单例的实现 2.1 基础要点 2.2 C++ 实现单例的几种方式 2.3 单例的模板 三.何时应该使用或者不使用单例 反对单例的理由 参考文 ...

随机推荐

  1. Azure上批量创建OS Disk大于30G的Linux VM

    Azure上VM的OS盘的大小在创建时是固定的.Windows是127G,Linux是30G.如果需要批量创建的VM的OS Disk有更大的容量.可以考虑用下面的方法实现. 1 创建一台有Data-d ...

  2. (转)更改Web.config中对上传文件大小限制

    .net上传超过200K的图片的时候,会跳转到404,但是url没有错误,真J8的坑啊. 本文转载自:http://www.cnblogs.com/zwffff/archive/2009/04/29/ ...

  3. SpringBoot之二:部署Spring Boot应用程序方式

    衡量多种部署方式 Spring Boot应用程序有多种构建和运行方式,其中一些你已经使用过了. 在IDE中运行应用程序(涉及Spring ToolSuite或IntelliJ IDEA). 使用Mav ...

  4. AngularJS:SQL

    ylbtech-AngularJS:SQL 1.返回顶部 1. AngularJS SQL 在前面章节中的代码也可以用于读取数据库中的数据. 使用 PHP 从 MySQL 中获取数据 AngularJ ...

  5. eclipse中创建包时变成文件夹,且文件夹内的类无法被其他类引用

    1.检查该文件夹是否已经被配置到了工程的build path里source folders ===>右键工程 选Build Path->Configure Build Path就可以看到 ...

  6. jdbcTemplate学习(三)

    上一节讲的查询方法,映射结果集为对象时,需要一个个set属性值,比较麻烦,下面讲解使用BeanPropertyRowMapper来将查询结果简单映射成对象: 使用Spring的JdbcTemplate ...

  7. js在浏览器下的区别小结(部分)

    1.初始化数组: document.write([1,2,3,].length); IE:4//把数组中最后一个逗号后面的当做了undefined元素 FF.Opera.Safari:3 2.join ...

  8. 【271】IDL-ENVI二次开发

    参考:String Processing Routines —— 字符串处理函数 01   STRING 返回字符串. 02   STRCMP 比较字符串,一样返回1,不一样返回0,默认大小写敏感. ...

  9. OSI七层网络模型与TCP/IP四层网络模型

    1.OSI网络7层模型 网络协议设计者不应当设计一个单一.巨大的协议来为所有形式的通信规定完整的细节,而应把通信问题划分成多个小问题,然后为每一个小问题设计一个单独的协议.这样做使得每个协议的设计.分 ...

  10. Python 网络爬虫 002 (入门) 爬取一个网站之前,要了解的知识

    网站站点的背景调研 1. 检查 robots.txt 网站都会定义robots.txt 文件,这个文件就是给 网络爬虫 来了解爬取该网站时存在哪些限制.当然了,这个限制仅仅只是一个建议,你可以遵守,也 ...