Expression Template(表达式模板,ET)
1.前言
在前一篇文章自己实现简单的string类中提到在实现+操作符重载函数时,为了防止返回时生成的临时对象调用拷贝构造函数动态申请内存空间,使用了一个叫move的函数,它是C++0x新增的特性。既然是C++0x新增的特性,那么在以前没有这个特性的情况下,对于临时对象动态申请内存空间的问题是不是可以有其它的方法解决或避免呢?答案是肯定的,可以用Expression Template(表达式模板,ET)来解决。
2.表达式模板
对于前面的String类,我们可能经常会使用下面的表达式:
String str4 = str1 + str2 + str3;
这个表达式有一个问题,就是产生了“不必要”的临时对象。因为 str1 + str2 的结果会存放在一个临时对象 temp1上,然后temp1 + str3的结果会存放在令一个临时对象temp2上,temp2最后把结果传给str4 进行初始化。如果这些向量很长,或者表达式再加几节,不仅会产生很多的临时对象,而且要动态申请内存空间来存放String内部的字符串,这很明显是低效的。move函数解决了当+操作符重载函数返回临时对象时,编译器在栈中为其拷贝另一个对象的开销(由于+操作符重载函数内声明的临时对象temp1在函数的作用域外事无法使用的,所以编译器自动的在调用+操作符重载函数的域内声明了一个临时对象temp11,用以存放拷贝的temp1),但并没有解决产生临时对象的问题。表达式模板的思路很简单,就是对+操作进行推迟计算,即一次性计算所有的+操作,这样就不需要产生临时对象来保存+操作的临时结果。由于要推迟计算,所以必须保存str1,str2,str3操作数用于后面真正计算推迟的+操作。
3.基于String的表达式模板实现
虽然表达式模板的思路很简单,但其实现确不是想象的那么简单。原来的做法中,operator + 直接进行了计算,既然我们不想它“过早”的计算,那么我们就必须重新重载一个operator + 运算符,在这个运算中不进行真正的运算,只是生成一个对象,在这个对象中把加法运算符两边的操作数保留下来,然后让它参与到下一步的计算中去。(好吧,这个对象也是临时的,但它的代价非常非常小,因为它不需要动态申请内存空间,我们先不理会它)。
class String; template <typename L>
class ExpPlus {
const L &lstr;
const char *rstr;
const int _size;
public:
ExpPlus(const L & a_l, const char *a_r):lstr(a_l), rstr(a_r), _size(strlen(a_r))
{
}
ExpPlus(const L & a_l, const char &a_r):lstr(a_l), rstr(&a_r), _size()
{
}
ExpPlus(const L & a_l, const String &a_r):lstr(a_l), rstr(a_r.c_str()), _size(a_r.size())
{
}
void copy_str(char *d_str) const;
int size() const
{
return _size + lstr.size();
}
}; template <typename L>
void ExpPlus<L>::copy_str(char *d_str) const
{
lstr.copy_str(d_str);
strncpy(d_str + lstr.size(), rstr, _size);
}
//用于+模板
template <typename L>
ExpPlus<L> operator + (const L & a_l, const char & a_r) {
return ExpPlus<L>(a_l, a_r);
} template <typename L>
ExpPlus<L> operator + (const L & a_l, const char* a_r) {
return ExpPlus<L>(a_l, a_r);
} template <typename L>
ExpPlus<L> operator + (const L & a_l, const String & a_r) {
return ExpPlus<L>(a_l, a_r);
}
我们增加了一个模板类 ExpPlus,用它来代表加法计算的“表达式”,但在进行加法时,它本身并不进行真正的计算。对这个类,定义了copy_str函数,在这个函数中才进行了真正的字符串加法计算。当然,它除了支持保存String对象,还支持保存char和char *。因为String对象加字符串常量和字符也是很常见的,如下面的表达式:
String str2 = str1 + 'a' + "cd"
对于我们实现的String类,必须重新重载一个operator = 函数,用于一次性计算右边表达式的值。修改后的String代码如下:
class String
{
public:
。。。
template <typename Exp>
String& operator=(const Exp &a_r); //新加
。。。
void copy_str(char *d_str) const; //新加
}; void String::copy_str(char *d_str) const
{
strcpy(d_str, _string);
} template <typename Exp>
String& String::operator=(const Exp &a_r)
{
char *temp_str;
int size = a_r.size(); temp_str = new char[size + ];
a_r.copy_str(temp_str);
temp_str[size] = ;
if (_string)
delete _string;
_string = temp_str;
_size = size;
return *this;
}
上面只给出了新加的代码,其它代码在自己实现简单的string类中已经给出。
上面这段话,对于不了解ET的人来说,也许一时间还不容易明白,我们一步一步来:
在 str4 = str1 + str2 + str3这个式子中,首先遇到 str1 + str2,这时,模板函数 operator + 会被调用,这时只是生成一个临时的ExpPlus<String>对象(我们叫它 t1 吧),不做计算,只是保留计算的左右操作数(也就是str1和str2),接着,t1 + str3 ,再次调用同样的 operator + ,而且也只是生成一个对象(我们叫它 t2 吧),这个对象的类型是 ExpPlus<ExpPlus<String>>,同样,t2 在这里只是保留了两边的操作数(也就是 t1 和 str3)。直到整个表达式“做完”,没有任何东西进行了计算,所做的事情实际上只是用 ExpPlus 这个模板类把计算式的信息记录下来了(当然,这些信息就是参与计算的操作数)。
最后,当进行 str4 = t2 的时候,String的赋值运算符被调用(用 t2 作参数)。注意,这个调用中的语句a_r.copy_str(temp_str),实际是是调用t2.copy_str(temp_str),t2.copy_str函数中又调用t1.copy_str,t1又调用str1.copy_str,就这样一步一步地将str1,str2,str3中的字符串拷贝到temp_str中,最终得到str4 = str1 + str2 + str3。就像变“魔术”一样,我们通过ExpPlus完成了“延迟计算”,并避免了大型的 String临时对象的产生。
4.总结
表达式模板保持了表达式直观和效率两者,很强大,但很显然它太复杂,主要是作为类库的设计者的武器。另外,它也可能使得使用者要理解一些“新”东西,比如,如果我想存储表达式的中间值,那么 <ExpPlus<ExpPlus<...<String>...> 一定会让使用者理解半天。
参考:http://www.cnblogs.com/liyiwen/archive/2009/12/03/1616627.html
http://www.cppblog.com/kesalin/archive/2009/05/28/85983.html
Expression Template(表达式模板,ET)的更多相关文章
- C++ template —— 表达式模板(十)
表达式模板解决的问题是:对于一个数值数组类,它需要为基于整个数组对象的数值操作提供支持,如对数组求和或放大: Array<), y(); ... x = 1.2 * x + x * y; 对效率 ...
- MShadow中的表达式模板
表达式模板是Eigen.GSL和boost.uBLAS等高性能C++矩阵库的核心技术.本文基于MXNet给出的教程文档来阐述MXNet所依赖的高性能矩阵库MShadow背后的原理. 编写高效的机器学习 ...
- .NET平台开源项目速览(8)Expression Evaluator表达式计算组件使用
在文章:这些.NET开源项目你知道吗?让.NET开源来得更加猛烈些吧!(第二辑)中,给大家初步介绍了一下Expression Evaluator验证组件.那里只是概述了一下,并没有对其使用和强大功能做 ...
- Atitit.java expression fsm 表达式词法分析引擎 v2 qaa.docx
Atitit.java expression fsm 表达式词法分析引擎 v2 qaa.docx C:\0workspace\AtiPlatf_cms\src\com\attilax\fsm\Java ...
- Atitit.java expression fsm 表达式分词fsm引擎
Atitit.java expression fsm 表达式分词fsm引擎 C:\0workspace\AtiPlatf_cms\src\com\attilax\fsm\JavaExpFsm.java ...
- IE css expression(表达式)
很多时候我们需要对IE6的bug写一些hack,如max-height,absolute元素高度100%等. css里面的 expression(表达式)和js里面的差不多,如: 获取当前元素的高度: ...
- art template前端模板引擎
偶然看到后台有一段代码 采用的是art template的模板引擎 地址为 http://aui.github.io/artTemplate/ 这段代码很简洁 var html = template( ...
- Template Method 模板设计模式
什么是模板设计模式 对于不了解的模板设计模式的来说,可以认为如同古代的造纸术一样,纸所以成型,取决于用了模板的形状,形状又由镂空的木板组成,而你想要造什么纸,又取决于你使用什么材料. 上面提到了两个关 ...
- Atitit.eclipse comment template注释模板
Atitit.eclipse comment template注释模板 1. Code templet1 1.1. Settpath1 1.2. 设置存储1 1.3. 导出设置1 2. Java d ...
随机推荐
- 简单谈谈如何利用h5实现音频的播放
作者:白狼 出处:http://www.manks.top/article/h5_audio本文版权归作者,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律 ...
- SEO:避免关键词内部竞争带来的无法收录问题,
站内关键词相互竞争在未经过搜索引擎优化的网站中常出现.许多人不理解搜索引擎对关键词的索引原理,以为在整站内频繁布局某几个热门关键词能提升这些词的排名. 一.搜索引擎希望展现多种多样的搜索结果 搜索引擎 ...
- Python操作Mysql数据库时SQL语句的格式问题
一.概述 近日使用Python对Mysql数据库进行操作,遇到SQL语句死活出问题的情况.由于最初没有将异常打印出来,一直不知道原因.随后,将异常打印出来之后,通过异常信息,对代码进行修改.最终,成功 ...
- Matlab 视频与图像之间的相互转换
matlab版本是2015b,其中更新了部分函数库之前网上相关程序不适用于新版本,在此提供适用于新版本的程序: 帧序列转换为视频 function video = frames2video(frame ...
- Swift 3 and OpenGL on Linux and macOS with GLFW
https://solarianprogrammer.com/2016/11/19/swift-opengl-linux-macos-glfw/ Swift 3 and OpenGL on Linux ...
- 20145337 GDB调试汇编堆栈过程分析
20145337 GDB调试汇编堆栈过程分析 测试代码 #include<stdio.h> short addend1 = 1; static int addend2 = 2; const ...
- C ReadProcessMemory
ReadProcessMemory函数用于读取其他进程的数据. BOOL STDCALL ReadProcessMemory ( HANDLE hProcess, LPCVOID lpBaseAddr ...
- 小知识 安卓线程和ui
*:first-child { margin-top: 0 !important; } body>*:last-child { margin-bottom: 0 !important; } /* ...
- SQL SERVER全面优化-------写出好语句是习惯
前几篇文章已经从整体提供了诊断数据库的各个方面问题的基本思路...也许对你很有用,也许你觉得离自己太远.那么今天我们从语句的一些优化写法及一些简单优化方法做一个介绍.这对于很多开发人员来说还是很有用的 ...
- 程序员的经济学系列——你不可不知的生存智慧——第一篇:小X是要成为IT精英的男人!
21世纪,不懂经济学就是耍流氓!如何才能生活得更好?作为程序员你一定也思考过这个问题.今天我们就来从经济学中寻找这问题的答案吧! 一·PPF与机会成本 1.PPF综述 首先为大家介绍第一个最简单的经济 ...