在阅读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. java bean Format注解用法

    @NumberFormat(style=Style.NUMBER)    private int number; @DateTimeFormat(pattern="yyyy-MM-dd&qu ...

  2. 【转】 Pro Android学习笔记(八四):了解Package(3):包间数据共享

    目录(?)[-] 共享User ID的设置 共享资源例子 文章转载只能用于非商业性质,且不能带有虚拟货币.积分.注册等附加条件.转载须注明出处:http://blog.csdn.net/flowing ...

  3. 学习vue

    一,声明模板的时候需要新建示例 如下代码 <div id="app"> <my></my> </div> Vue.component ...

  4. PostgreSQL 管理数据库

    管理数据库每个正在运行的PostgreSQL 服务器实例都管理着一个或多个数据库.因此,在组织SQL对象(“数据库对象”)的层次中,数据库位于最顶层. 本章描述数据库的属性,以及如何创建.管理.删除它 ...

  5. mariaDB 安装/卸载+启动/关闭 服务

    1.设置环境变量 无论是用户环境变量还是系统环境变量 2.启动服务 进入根目录 名字根据 --install 后的 参数来决定 叫MariaDB,MySQL 都可以 mysqld.exe --inst ...

  6. 【转】onclick事件与href='javascript:function()'的区别

    href='javascript:function()'和onclick能起到同样的效果,一般来说,如果要调用脚本还是在onclick事件里面写代码,而不推荐在href='javascript:fun ...

  7. WINDOWS 7下的记事本程序目录

    这是win7的目录    系统所在分区:\Windows\system32\notepad.exe

  8. Celery-4.1 用户指南: Daemonization (系统守护进程)

    Generic init-scripts 查看Celery发布里的 extra/generic-init.d/ 文件夹. 这个文件夹中包含了celery worker 程序的通用bash初始化脚本,可 ...

  9. Ubuntu下设置VNCServer

    Ubuntu下设置VNCServer Virtual Network Computing(VNC)是进行远程桌面控制的一个软件.客户端的键盘输入和鼠标操作通过网络传输到远程服务器,控制服务器的操作.服 ...

  10. Diag:Diagonal matrices and diagonals of a matrix

    Diag:Diagonal matrices and diagonals of a matrix Syntax X = diag(v,k) X = diag(v) v = diag(X,k) v =  ...