注:原创不易,转载请务必注明原作者和出处,感谢支持!

注:内容来自某培训课程,不一定完全正确!

一 STL容器共性机制

STL容器所提供的值都是值(value)寓意,而非引用(reference)寓意,也就是说当我们给容器中插入元素的时候,容器内部实施了拷贝动作,将我们要插入的元素再另行拷贝一份放入到容器中,而不是将原数据元素的引用放入容器中,也就是说我们提供的元素必须能够被拷贝。

(1)除了queue和stack之外,每个容器都提供可返回迭代器的函数,运用返回的迭代器就可以访问元素。

(2)通常STL不会抛出异常,需要使用者传入正确参数

(3)每个容器都提供了一个默认构造函数和默认的拷贝构造函数。

(4)大小相关的方法:size()返回容器中元素的个数,empty()判断容器是否为空

二 STL容器的使用场合

vector deque list set multiset map multimap
典型内存结构 单端数组 双端数组 双向链表 二叉树 二叉树 二叉树 二叉树
可随机存取 对key而言:是
元素搜索速度 非常慢 对key而言:快 对key而言:快
元素插入和删除 尾端 头尾两端 任何位置 - - - -

(1)vector容器的使用场景:比如软件历史操作记录的存储。

(2)deque的使用场景:比如排队购票系统,对排队者的存储可以采用deque,支持头端的快速移除,尾端的快速添加。

vector和deque的比较:

  • vector.at()比deque.at()效率高,比如vector.at(0)是固定的,deque的开始位置却是不固定的。
  • 如果有大量的释放操作的话,vector花的时间更少,这和二者的内部实现有关。
  • deque支持头部的快速插入和删除,这是deque的优点。

(3)list的使用场景:比如公交乘客的存储,随时可能有乘客下车,支持频繁的不确定位置元素的移除。

(4)set的使用场景:比如对手机游戏的个人得分记录的存储,存储要求从高分到低分的顺序排列。

(5)map的使用场景:比如按ID号存储十万个用户,想要快速通过ID查找对应的用户,二叉树的查找效率就体现出来了。

三 函数对象

重载函数调用操作符的类,其对象常被称为函数对象(function object),即它们是行为类似函数的对象,也叫仿函数(functor),其实就是重载“()”操作符,使得类对象可以像函数那样调用。

注意:

(1)函数对象(仿函数)是一个类,不是一个函数

(2)函数对象重载了“()”操作符使得它可以像函数一样调用

假定某个类有一个重载的operator(),而且重载的operator()要求获取一个参数,我们就将这个类称为“一元仿函数(unary functor)”;相反,如果重载的operator()要求获取两个参数,我们就将这个类称为“二元仿函数(binary functor)”。

下面是函数对象的应用实例。

// 仿函数
class MyPrint
{
public:
MyPrint() { cnt = 0; }
void operator()(int val)
{
cout << val << endl;
++cnt;
}
unsigned getCnt() { return cnt; } private:
unsigned cnt;
}; void Test1()
{
// 函数对象可以像普通函数那样调用
// 函数对象可以像普通函数那样接受参数
// 函数对象超出了函数的概念,函数对象可以保存函数的调用状态
MyPrint PRINT;
PRINT(10); // 打印调用次数,使用函数对象可以避免使用全局变量
cout << "调用次数:" << PRINT.getCnt() << endl;
} void Test2()
{
vector<int> v;
v.push_back(10);
v.push_back(20);
v.push_back(30);
v.push_back(40); MyPrint PRINT = for_each(v.begin(), v.end(), MyPrint());
cout << "调用次数:" << PRINT.getCnt() << endl;
}

你虽然避免了使用全局变量,但是却要求共用PRINT对象?

四 谓词

谓词是指普通函数或者重载的operator()返回值是bool类型的函数对象(仿函数)。如果operator()接受一个参数,那么叫做一元谓词,如果接受两个参数,那么叫做二元谓词,谓词可以作为一个判断式。

举例:

一元函数对象:for_each

一元谓词:find_if

二元函数对象:transform

二元谓词:sort

五 内建函数对象

STL内建了一些函数对象。分为:

(1)算术类函数对象

(2)关系运算符类函数对象

(3)逻辑运算类函数对象

这些仿函数所产生的对象,用法和一般函数完全相同,当然我们还可以产生无名的临时对象来履行函数的功能。使用内建函数对象,需要引入头文件#include <functional>

6个算术类函数对象,除了negate是一元运算,其他都是二元运算。

template<class T> T plus<T>			// 加
template<class T> T minute<T> // 减
template<class T> T multiplies<T> // 乘
template<class T> T divides<T> // 除
template<class T> T modulus<T> // 取模
template<class T> T negate<T> // 取反

6个关系运算类函数对象,每一种都是二元运算。

template<class T> bool equal_to<T>			// 等于
template<class T> bool not_equal_to<T> // 不等于
template<class T> bool greater<T> // 大于
template<class T> bool greater_equal<T> // 大于等于
template<class T> bool less<T> // 小于
template<class T> bool less_equal<T> // 小于等于

逻辑运算类函数对象,not为一元运算,其余为二元运算

template<class T> bool logical_and<T>		// 逻辑与
template<class T> bool logical_or<T> // 逻辑或
template<class T> bool logical_not<T> // 逻辑非

六 函数对象适配器

函数对象适配器是完成一些配接工作,这些配接工作包括绑定(bind),否定(negate)以及对一般函数或成员函数的修饰,使其成为函数对象。

bind2st:将参数绑定为函数对象的第一个参数
bind2nd:将参数绑定为函数对象的第二个参数
not1:对一元函数对象取反
not2:对二元函数对象取反 ptr_fun:将普通函数修饰成函数对象
mem_fun:修饰成员函数
mem_fun_ref:修饰成员函数

函数适配器的应用案例。

struct MyPrint : public binary_function<int, int, void>
{
void operator()(int val, int add) const
{
cout << "val = " << val << " add = " << add << " val + add = " << val + add << endl;
}
}; // 仿函数适配器 bind1st bind2nd 绑定适配器
void Test1()
{
vector<int> v;
for (int i = 0; i < 10; ++i)
{
v.push_back(i);
} // for_each()在位置3只能填入一个参数,如果需要传入多个参数
// 那么你需要用到绑定适配器,绑定适配器的作用是将二元函数对象
// 转变成一元函数对象。
int add = 200;
for_each(v.begin(), v.end(), bind2nd(MyPrint(), add)); // bind1st,将add的值200绑定为第一个参数val
// bind2nd,将add的值200绑定为第二个参数add } // 仿函数适配器 not1 not2 取反适配器
struct MyCompare : public binary_function<int, int, bool>
{
// 从大到小排序
bool operator()(int v1, int v2) const
{
return v1 > v2;
}
}; struct MyPrint2
{
void operator()(int v) const
{
cout << v << " ";
}
}; // 大于5
struct MyGreater5 : public unary_function<int, bool>
{
bool operator()(int v) const
{
return v > 5;
}
}; void Test2()
{
vector<int> v;
for (int i = 0; i < 10; ++i)
{
v.push_back(rand() % 100 + 10);
} for_each(v.begin(), v.end(), MyPrint2());
cout << endl;
sort(v.begin(), v.end(), not2(MyCompare()));
for_each(v.begin(), v.end(), MyPrint2());
cout << endl; // 如果对二元谓词取反,用not2
// 如果对一元谓词取反,用not1 // 使用not1()将条件由大于5改为小于等于5
vector<int>::iterator ret = find_if(v.begin(), v.end(), not1(MyGreater5()));
if (ret != v.end())
{
cout << *ret << endl;
}
else
{
cout << "没有找到!" << endl;
}
} // 仿函数适配器 ptr_fun
void MyPrint3(int val, int add)
{
cout << "val = " << val << " add = " << add << endl;
} void Test3()
{
vector<int> v;
for (int i = 0; i < 10; ++i)
{
v.push_back(i);
} // 无法直接对函数MyPrint3()进行参数绑定
// for_each(v.begin(), v.end(), MyPrint3); // 把普通函数适配成函数对象,再进行参数绑定
for_each(v.begin(), v.end(), bind2nd(ptr_fun(MyPrint3), 10));
} // 成员函数适配器 mem_fun mem_fun_ref
class Person
{
public:
Person(int age, int id) : age(age), id(id) {}
void show()
{
cout << "age = " << age << " id = " << id << endl;
} public:
int age;
int id;
}; void Test4()
{
// 如果容器中存放的对象或者对象指针,我们for_each算法
// 打印的时候调用类自己提供的打印函数 vector<Person> v;
Person p1(10, 20), p2(30, 40), p3(50, 60), p4(70, 80);
v.push_back(p1);
v.push_back(p2);
v.push_back(p3);
v.push_back(p4);
// 没有提供额外的打印函数,调用Person自己的成员函数show()
// 格式: &类名::函数名
for_each(v.begin(), v.end(), mem_fun_ref(&Person::show));
cout << endl << endl; // 存储的是对象指针,用mem_fun
vector<Person *> v1;
v1.push_back(&p1);
v1.push_back(&p2);
v1.push_back(&p3);
v1.push_back(&p4);
for_each(v1.begin(), v1.end(), mem_fun(&Person::show)); // 如果存放的是对象,使用mem_fun_ref
// 如果存放的是对象指针,使用mem_fun
}

C++ STL——C++容器的共性和相关概念的更多相关文章

  1. c++复习:STL之容器

    1 STL的string 1 String概念 string是STL的字符串类型,通常用来表示字符串.而在使用string之前,字符串通常是用char*表示的.string与char*都可以用来表示字 ...

  2. [C++ STL] 各容器简单介绍

    什么是STL? 1.STL(Standard Template Library),即标准模板库,是一个高效的C++程序库. 2.包含了诸多常用的基本数据结构和基本算法.为广大C++程序员们提供了一个可 ...

  3. C++ STL vector容器学习

    STL(Standard Template Library)标准模板库是C++最重要的组成部分,它提供了一组表示容器.迭代器.函数对象和算法的模板.其中容器是存储类型相同的数据的结构(如vector, ...

  4. STL List容器

    转载http://www.cnblogs.com/fangyukuan/archive/2010/09/21/1832364.html 各个容器有很多的相似性.先学好一个,其它的就好办了.先从基础开始 ...

  5. STL之容器适配器queue的实现框架

    说明:本文仅供学习交流,转载请标明出处,欢迎转载! 上篇文章STL之容器适配器stack的实现框架已经介绍了STL是怎样借助基础容器实现一种经常使用的数据结构stack (栈),本文介绍下第二种STL ...

  6. STL的容器算法迭代器的设计理念

    1) STL的容器通过类模板技术,实现数据类型和容器模型的分离. 2) STL的迭代器技术实现了遍历容器的统一方法:也为STL的算法提供了统一性. 3) STL的函数对象实现了自定义数据类型的算法运算 ...

  7. stl之容器、迭代器、算法几者之间的关系

    转自:https://blog.csdn.net/bobodem/article/details/49386131 stl包括容器.迭代器和算法: 容器 用于管理一些相关的数据类型.每种容器都有它的优 ...

  8. STL Queue 容器

    STL Queue 容器 Queue简介         queue是队列容器,是一种“先进先出”的容器.         queue是简单地装饰deque容器而成为另外的一种容器.        # ...

  9. STL stack 容器

    STL stack 容器 Stack简介 stack是堆栈容器,是一种“先进后出”的容器.      stack是简单地装饰deque容器而成为另外的一种容器.      #include <s ...

随机推荐

  1. 第四章、Django之模型层---创建模型

    目录 第四章.Django之模型层---创建模型 一.写models.py 第四章.Django之模型层---创建模型 一.写models.py from django.db import model ...

  2. oracle内核参数详解

    一.前言 在生产中,我们安装oracle数据库时,为达到最优我们需要对操作系统的内核参数进行一定的调整.主要从内存.cpu.io以及网络等方面,根据实际情况进行调整.以下参数可供大家参考,如有不当之处 ...

  3. Django—ModelForm

    简介 Model + Form ==> ModelForm.model和form的结合体,所以有以下功能: 验证 数据库操作 Form回顾 models.py class UserType(mo ...

  4. Vsftpd Nginx

    Linux(CentOS-6.10)下安装Vsftpd Nginx 1:创建FTP专属的账户和密码[root@localhost ~]# useradd ftpuser[root@localhost ...

  5. java_变量和常量

    一.变量(可以改变的量) 1.命名规则: a.遵循标识符命名规则: 1.关键字是不能用作标识符的 2.区分大小写 3.可以包含数字.字母.下划线.美元符号$,但是不能以数字作为开头 b.尽量使用有意义 ...

  6. oracle 初试 hint

    最近在研究oracle的视图问题,本来想全转成 物化视图(materialized view)的,这样可以极大提升系统的响应时间,无奈工作量太大,所以就研究了SQL优化的问题. 我这个普通视图 有36 ...

  7. 说一下 HashSet 的实现原理?(未完成)

    说一下 HashSet 的实现原理?(未完成)

  8. Mac环境下使用Appium Inspector进行元素定位

    一.摘要 本篇博文介绍在Mac系统上使用AppiumI Inspector进行App页面元素定位 二.Finding elements by xpath WebElement digit_9 = dr ...

  9. 下划线文字,鼠标hover小样式

    CSS样式 //不只是a标签,其他有下划线的字体也可以 a:hover{ color: #ff3100; //这里的颜色是指字体颜色不是波浪下划线效果的svg图颜色     text-decorati ...

  10. Navicat Premium 12连接mysql-8.0.15-winx64 出现2059异常

    错误