CPP笔记_泛型编程简单总结
本篇是基于《Essential C++》第三章泛型编程风格的一个简单总结
1 Iterator
vector<string>::iterator 表明此iterator是位于string vector定义内的一个嵌套类型;
vector<string>::const_iterator 只容许我们读取vector内的元素,但不容许任何写入操作;
2 容器
所有容器都支持的操作有:
- “==”和“!=”操作符,返回true或者false
- assignment(=)运算符,将一个容器复制给另一个容器。这是深度复制,而不是简单的引用。比如vector<int> ori; ori.insert(1); vector<int> copied = ori; ori.clear(); cout<<ori.size()<<" "<<copied.size(); 那么将输出“0 1”
- empty():当容器内无任何元素时返回true,否则false
- size():返回容器内目前持有的元素个数
- clear():删除所有元素
- begin():返回一个指向容器内第一个元素的iterator
- end():返回一个指向容器内最后一个元素的下一个位置的iterator
- insert():将单一或者某个范围内的元素插入容器内
- erase():将容器内的单一元素或者某个范围内的元素删除
|
容器 |
Vector |
list |
Deque |
|
存储方式 |
连续内存 |
双向链接 |
连续内存 |
|
插入/删除 |
对末端的插入和删除效率很高,而对非末端的插入删除则由于需要大量复制而效率很低 |
对任意位置的插入删除都效率高 |
对头、尾的插入删除都效率高 |
|
随机读取 |
高 |
低 |
高 |
|
支持操作 |
push_back() pop_back() |
push_back() pop_back() push_front() pop_front() |
push_back() pop_back() push_front() pop_front() |
|
Pop操作并不返回删除的元素,要获取对应的元素,可以分别调用back(), front() |
|||
3 Function Object
技术背景:在定义一些泛型函数时,可能需要使用者传入一些比如less_than这样的函数指针,例如:
//一个小于比较器
bool less_than(int v1, int v2)
{
return v1 < v2 ? ture : flase;
} //用来从原vec中过滤基于pred比较结果的数。pred即为使用这需要传入的指明比较意义的函数指针。
vector<int> vec_filter(const vector<int> &vec, const int threshold, bool (*pred) (int, int))
{
vector<int> result;
for (int i = ; i < vec.size(); ++i)
{
if(pred(vec[i], threshold))
{
result.push_back(vec[i]);
}
}
return result;
}
我在使用vec_filter(vec, 100, less_than)的时候,就会得到一个把原vec中所有小于100的数的提取出来的result。但是这样的话,效率不高,因为在vec_filter的if判断中是通过函数指针来调用函数的。要是能使用inline就好了。function object就是为了这个而设计出来的。使用function object就可以让这个调用成为inline调用,提高效率。
为了使用function object,应该包含头文件#include<functional>,在标准库中定义了一组function object,包括算术运算、关系运算和逻辑运算三个类别:
- 六个算术运算:plus<type>, minus<type>, negate<type>, multiplies<type>, divides<type>, modules<type>
- 六个关系运算:less<type>, less_equal<type>, greater<type>, greater_equal<type>, equal_to<type>, not_equal_to<type>
- 三个逻辑运算:logical_and<type>, logical_or<type>, logical_not<type>
sample代码:
//一个小于比较器
bool less_than(int v1, int v2)
{
return v1 < v2 ? true : false;
} //用来从原vec中过滤基于pred比较结果的数。pred即为使用这需要传入的指明比较意义的函数指针。
template<typename Comp>
vector<int> vec_filter(const vector<int> &vec, const int threshold, Comp pred)
{
vector<int> result;
for (int i = ; i < vec.size(); ++i)
{
if(pred(vec[i], threshold))
{
result.push_back(vec[i]);
}
}
return result;
} int main()
{ vector<int> vecint();
for(int i = ; i < ; ++i)
{
vecint.push_back(i);
}
vector<int> result = vec_filter(vecint, , less_than);
cout<<result.size()<<" "<<vecint.size()<<endl;
result = vec_filter(vecint, , less<int>());
cout<<result.size()<<" "<<vecint.size()<<endl;
}
可能标准库提供的function object不能满足需求,标准库还提供了两个bingder adapter(绑定适配器)。这两个绑定器的作用都是将一元function object变成function object,其中bind1st将指定值绑定到第一个参数,bind2nd将指定值绑定到第二个参数,示例代码:
template<typename Comp>
vector<int> vec_filter(const vector<int> &vec, Comp pred)
{
vector<int> result;
for (int i = ; i < vec.size(); ++i)
{
if(pred(vec[i]))
{
result.push_back(vec[i]);
}
}
return result;
} int main()
{ vector<int> vecint;
for(int i = ; i < ; ++i)
{
vecint.push_back(i);
}
vector<int> result = vec_filter(vecint, bind1st(less<int>(), ));
cout<<result.size()<<" "<<vecint.size()<<endl; //54 100
binder2nd<less<int>> bind2 = bind2nd(less<int>(), );
result = vec_filter(vecint, bind2);
cout<<result.size()<<" "<<vecint.size()<<endl; //45 100
}
我们可以在7行的if中,pred就只需要传入一个参数了。而且对比bind1st和bind2nd两个函数的效果,bind1st因为把45绑定在第一个参数,那么在if中,只要vec[i]比45大,条件就会成立,所以输出54。同理,bind2nd输出45.
如何自定义一个function object?
当编译器遇到一个语句 lt(ival); 的时候,lt可能是什么?有三种可能:函数名称,函数指针,还有一种可能就是一个提供了function call运算符的的function object,即lt是一个class object。那么编译器将把上述语句自动转换为:lt.operator(ival); 因此,自定义function object的关键也就出来了,就是定义一个operator()运算符。
class LessThan{
private:
int mVal;
public:
LessThan(int val){mVal = val;}
/************************************************************************/
/* 特征。0:operator()操作符; 1:inline;2:const函数; */
/************************************************************************/
inline bool operator()(int val) const {return val < mVal;};
};
4 Iterator Inserter
背景问题:在所有“会对元素进行复制行为”的泛型算法中,比如copy(), copy_backwards(), remove_copy(), replace_copy(), unique_copy()等等,他们的实现中每复制一个元素,都会使用赋值(assignment, =)来实现,那么就存在一个问题,即目标容器的容易必须足够大,否则就会产生溢出错误。即对使用者提出了这样的一个要求:保证目的容器的容量足够大。比如下面代码就会报错:
vector<int> vecint;
for(int i = ; i < ; ++i)
{
vecint.push_back(i);
}
vector<int> vec2; //假如改为vector<int> vec2(vecint.size())则会正常运行
copy(vecint.begin(), vecint.end(), vec2.begin());
STL为了能够消除使用者的这个负担,提供了三个insertion adapter:back_inserter(), inserter(), front_inserter()(由于vector并没有push_front(),所以这个只使用于list和deque), 他们会分别使用push_back(),insert()和push_front()来替代赋值(=)操作。示例代码:
vector<int> vecint;
for(int i = ; i < ; ++i)
{
vecint.push_back(i);
}
vector<int> vec2;
copy(vecint.begin(), vecint.end(), back_inserter(vec2));
cout<<vec2.size(); //输出100
5 Iostream Iterator
效果:使用iterator来替代输入输出流的表达方式。标准库中提供istream_iterator和ostream_iterator两个类来分别支持单一类型的元素读取和写入,使用时应该先#include <iterator>。示例代码:
//从cin中输入单词,然后写入到文件word.txt
//常用表达方式
string word;
vector<string> vec_word;
while (cin>>word)
{
vec_word.push_back(word);
}
ofstream out_file("word.txt");
for (int i = ; i < vec_word.size(); ++i)
{
out_file<<vec_word[i] <<" ";
} //使用iostream iterator
istream_iterator<string> str_in(cin); //创建输入流迭代器,可以从任何输入流创建
istream_iterator<string> eof;
copy(str_in, eof, vec_word);
//创建输出流迭代器,可以从任何输出流创建
ostream_iterator<string> out_file_itr(ofstream("word.txt"), " ");
copy(vec_word.begin(), vec_word.end(), out_file_itr);
CPP笔记_泛型编程简单总结的更多相关文章
- CPP笔记_函数返回局部变量
本篇笔记记录的是关于返回函数中的局部值. 我们知道,在函数中创建的局部变量会随着函数的调用过程的结束,也即其对应函数栈帧的清除,而结束其生命周期.那么,如果我们把这个局部变量返回,就有可能存在该变量对 ...
- React笔记_(3)_react语法2
React笔记_(3)_react语法2 state和refs props就是在render渲染时,向组件内传递的变量,这个传递是单向的,只能继承下来读取. 如何进行双向传递呢? state (状态机 ...
- how tomcat works 读书笔记(二)----------一个简单的servlet容器
app1 (建议读者在看本章之前,先看how tomcat works 读书笔记(一)----------一个简单的web服务器 http://blog.csdn.net/dlf123321/arti ...
- Python编程从入门到实践笔记——变量和简单数据类型
Python编程从入门到实践笔记——变量和简单数据类型 #coding=gbk #变量 message_1 = 'aAa fff' message_2 = 'hart' message_3 = &qu ...
- 《Essential C++》读书笔记 之 泛型编程风格
<Essential C++>读书笔记 之 泛型编程风格 2014-07-07 3.1 指针的算术运算(The Arithmetic of Pointer) 新需求1 新需求2 新需求3 ...
- Spring MVC 学习笔记10 —— 实现简单的用户管理(4.3)用户登录显示全局异常信息
</pre>Spring MVC 学习笔记10 -- 实现简单的用户管理(4.3)用户登录--显示全局异常信息<p></p><p></p>& ...
- Spring MVC 学习笔记9 —— 实现简单的用户管理(4)用户登录显示局部异常信息
Spring MVC 学习笔记9 -- 实现简单的用户管理(4.2)用户登录--显示局部异常信息 第二部分:显示局部异常信息,而不是500错误页 1. 写一个方法,把UserException传进来. ...
- Spring MVC 学习笔记8 —— 实现简单的用户管理(4)用户登录
Spring MVC 学习笔记8 -- 实现简单的用户管理(4)用户登录 增删改查,login 1. login.jsp,写在外面,及跟WEB-INF同一级目录,如:ls Webcontent; &g ...
- 读经典——《CLR via C#》(Jeffrey Richter著) 笔记_发布者策略控制
在 读经典——<CLR via C#>(Jeffrey Richter著) 笔记_高级管理控制(配置)中,是由程序集的发布者将程序集的一个新版本发送给管理员,后者安装程序集,并手动编辑应用 ...
随机推荐
- .NET客户端实现Redis中的管道(PipeLine)与事物(Transactions)
序言 Redis中的管道(PipeLine)特性:简述一下就是,Redis如何从客户端一次发送多个命令,服务端到客户端如何一次性响应多个命令. Redis使用的是客户端-服务器模型和请求/响应协议的T ...
- 分享小知识:善用Group By排序
以下列举了公用表/临时表/聚合函数三个因素为例子(覆盖索引因素除外,有利用此类索引都会以索引顺序) 环境: Microsoft SQL Server 2014 (SP1-GDR) (KB319472 ...
- 【WCF】错误处理(二):错误码―—FaultCode
先来说说SOAP消息中错误消息的包装结构,一条SOAP错误消息的大致形式如下: <s:Fault> <faultcode xmlns:a="me-cust-error&qu ...
- 关于web测试收集
页面部分 页面清单是否完整(是否已经将所需要的页面全部都列出来了) 页面是否显示(在不同分辨率下页面是否存在,在不同浏览器版本中页面是是否显示) 页面在窗口中的显示是否正确.美观(在调整浏览器窗口大小 ...
- PHP随机生成随机个数的字母组合示例
在很多系统环境下大家都会用到字母组合各种编码,下面推荐大家非常实用的PHP代码. $num由几个字母组合. $s字母包含大小写,可以自己调配大写还小写. <?php function makec ...
- kvm基本原理
KVM源代码分析1:基本工作原理 下了很大决心挖这个坑,虽然之前对kvm有些了解,但纸上得来终觉浅,只有深入到代码层面,才能摈弃皮毛,看到血肉,看到真相.作为挖坑的奠基石,准备写上几篇:kvm基本工作 ...
- HTML5本地图片裁剪并上传
最近做了一个项目,这个项目中需要实现的一个功能是:用户自定义头像(用户在本地选择一张图片,在本地将图片裁剪成满足系统要求尺寸的大小).这个功能的需求是:头像最初剪切为一个正方形.如果选择的图片小于规定 ...
- C# 6 与 .NET Core 1.0 高级编程 - 41 ASP.NET MVC(下)
译文,个人原创,转载请注明出处(C# 6 与 .NET Core 1.0 高级编程 - 41 ASP.NET MVC(下)),不对的地方欢迎指出与交流. 章节出自<Professional C# ...
- 《用Python做HTTP接口测试》学习感悟
机缘巧合之下,报名参加了阿奎老师发布在"好班长"的课程<用Python做HTTP接口测试>,报名费:15rmb,不到一杯咖啡钱,目前为止的状态:坚定不移的跟下去,自学+ ...
- 用Java实现将多级文件夹下的所有文件统一放到一个文件夹中
每次下了电影(男生懂得呦),每部电影都放在一个单独的文件夹里,看的时候很是不方便啊,一直重复着进入文件夹.后退,再进.再退的操作,而手动把这些电影全部复制出来又太繁琐.因此为了解决这个问题,用IO写了 ...