`
jamie.wang
  • 浏览: 347704 次
  • 性别: Icon_minigender_1
  • 来自: 成都
社区版块
存档分类
最新评论

The C++ Standard Library 学习笔记(一)第5章

 
阅读更多

5. 标准模板库

5.1 STL组件

容器,泛型容器,管理对象的集合

迭代器,遍历容器对象的辅助对象,由各个容器提供。

算法,与具体容器分离,运用迭代器操作容器内对象。

STL主张将容器与算法分离,使得算法可以抽象与容器之上,同时操作不同类型的容器,但需要容器提供迭代器。

STL容器只提供效率高的方法,因此不同容器提供的方法可能不一样。

STL是最好的泛型编程的参考资料。

5.2 容器

两种容器

1. 顺序容器Sequence Containers),元素的位置是确定的,和插入容器的顺序一致。这类容器有:vector, deque, list.

2. 关联容器Associative Containers),元素是经过排列的,位置和元素的值,排序算法相关,这类容器有:set, multiset, map, multimap.

5.2.1 顺序容器(Sequence Containers

vector

可以把vector看成是动态数组,在很多实现中,vector的数据部分就是动态数组。它的元素可以随机访问,可以用下标操作符访问。在它的末尾添加和删除元素的速度非常快,而在开始或中间就比较耗时,因为它需要移动元素。适合于访问频繁,而插入、删除操作较少的需求。

Deque

deque是双向队列(double-ended queue)的缩写。顾名思义,deque在头和尾插入元素是非常快的,而在中间则较慢。

List

list这里是双向链表,它不能被随机访问,因此它的访问时间是线性的,而它在任何位置插入和删除元素的时间却是常数时间。

5.2.2 关联容器(Associative Containers

关联容器会自动将它的元素按某个条件(比较各个元素的key的大小)排序。关联容器一般都是以二叉树(binary tree)为基础实现

关联容器有:setmutiset, map, mutimap.

5.2.3 容器适配器(Container Adapters

STL提供了下面三种容器适配器:

Stack, Queue, Priority Queue.

5.3迭代器

容器的基本操作,适合于所有容器:

operator*operator++operator==operator!=and operator=

容器同时也提供了基本的方法去初始化和遍历容器:

begin(), end()

容器都有两种迭代器:

container::iterator,和container::const_iterator

5.3.2 迭代器分类

一般情况下,如果容器可以随机访问,那么它的迭代器也可以随机访问。

迭代器根据其访问规则可分为:

1. 双向迭代器(Bidirectional iterator

它只能递增或递减来向前或向后访问,这些迭代器的容器有:listsetmutisetmap,和mutimap

2. 随机访问迭代器(Random access iterator

它除了能像双向迭代器一样前后访问外,它还能通过算数运算随机访问元素,并且能使用比较操作符如< >,这些迭代器的容器有:vectordeque,以及string

5.4 算法

算法是STL中的全局函数,它可以通过迭代器操作STL的不同容器,甚至用户自定义的容器。

5.4.1 范围

算法所操作的元素都是以迭代器所表示的一个范围,它使得算法的运用更加灵活,但同时带来了危险:越界,这个需要程序员去保证。

算法所接受的范围都是一个迭代器指定的半开半闭的区间,即:[beginend

5.5 迭代器适配器

5.5.1 输入迭代器(Insert Iterator

输入迭代器常用于算法的输出参数,它使得算法输出到一个能自动扩展空间的容器中,插入这个容器的位置由该迭代器指定。

1. Back Inserter

back_inserter调用容器的push_back方法,将元素追加到容器中,因此它只能适用于支持push_back方法的容器,如:vector

2. Front Inserter

同样,front_inserter调用容器的push_front方法,将元素添加到容器开始,只适用于支持push_front方法的容器,如:dequelist

3. Inserter

inserter将元素插入到,第二个参数指定的元素之前。只有他是可以用于关联容器的。

5.5.2 流迭代器(Stream Iterator

流迭代器是一种从流(标准输入/输出,文件流等)中读取元素,或向流中写入元素。

5.5.3 反向迭代器(Reverse Iterator

顾名思义,它逆向访问元素。所有的容器可以用rbegin(),和rend()来创建反向迭代器。

5.5.4 迭代器的例子

#include <iostream>

#include <vector>

#include <list>

#include <deque>

#include <set>

#include <algorithm>

using namespace std;

int main(int argc, char* argv)

{

const int N = 10;

//prepare elements

vector<int> ivec;

ivec.reserve(N);

for (int i = 0; i < N; ++i)

{

ivec.push_back(i);

}

//inserter iterator

list<int> il;

copy(ivec.begin(), ivec.end(), back_inserter(il));

deque<int> id;

copy(il.begin(), il.end(), front_inserter(id));

set<int> is;

copy(id.begin(), id.end(), inserter(is, is.begin()));

//stream iterator

//output will be: 0 1 2 3 4 5 6 7 8 9

copy(is.begin(), is.end(), ostream_iterator<int>(cout, " "));

cout << endl;

//reverse iterator

//output will be: 9 8 7 6 5 4 3 2 1 0

copy(il.rbegin(), il.rend(), ostream_iterator<int>(cout, " "));

cout << endl;

getchar();

return 0;

};

输出:

0 1 2 3 4 5 6 7 8 9

9 8 7 6 5 4 3 2 1 0

5.6 操作算法

5.6.1 删除元素

算法remove实际并不删除元素,而是将等于删除值的 位置用后面的元素覆盖掉,然后返回剩余元素的最后一个位置的迭代器。真正要删除元素,则要调用容器(顺序容器)的erase方法

例子:

#include <algorithm>

#include <list>

#include <iostream>

template<class Container>

void print(const Container& c, const char* promption)

{

cout << promption << endl;

copy(c.begin(), c.end(), ostream_iterator<Container::value_type>(cout, " "));

cout << endl;

}

using namespace std;

int main()

{

list<int> il;

//prepare elements

for (int i = 0; i < 6; ++i)

{

il.push_back(i);

il.push_front(i);

}

//print the original elements

print(il, "original elements:");

//call remove

list<int>::iterator end = remove(il.begin(), il.end(), 3);

//print the elements after remove

print(il, "after remove:");

//print number of elements

cout << "Number of removed elements: " << distance(end, il.end()) << endl;

//remove the removed elements

il.erase(end, il.end());

//print the elements after real remove

print(il, "after erase:");

//for 5.6.3

//call member function to get better performance

il.remove(4);

//print the elements after remove 4

print(il, "removed 4:");

getchar();

return 0;

}

输出:

original elements:

5 4 3 2 1 0 0 1 2 3 4 5

after remove:

5 4 2 1 0 0 1 2 4 5 4 5

Number of removed elements: 2

after erase:

5 4 2 1 0 0 1 2 4 5

removed 4:

5 2 1 0 0 1 2 5

5.6.2 操作算法和关联容器

注意不能将关联容器作为算法操作的目标容器,因为关联容器的元素的位置是自动排序后的树形结构,操作算法会破坏它的结构。

而关联容器提供了成员函数做诸如remove之类的操作。

5.6.3 成员函数vs 算法

结论:成员函数优先于算法的调用。

5.8 算法的函数参数

5.8.2 Predicates

Predicates即是返回bool值的函数参数,它可能是二元的,也可能是一元的,他们通常是排序或搜索的条件。STLpredicates有特定的要求,对同一个值predicate必须返回同样的结果。

5.9 函数对象(Function Object

函数对象又称为仿函数(Functor),它也可以作为算法的函数参数。

5.9.1 什么是函数对象

函数对象是行为像函数的对象,因此它必须可以想调用函数那样调用它,也因此它必须重载括号(())操作符。

函数对象的定义格式:

class Functor

{

public:

//overload operator ()

return_type operator()(arguments) const

{

...

}

};

为什么要使用函数对象,他的优势在哪里呢

1. 函数对象是智能函数

因为它是一个对象,因此它可以有成员函数,和成员变量,同时可以被实例化以应对不同的需求。

2. 每个函数对象有它自己的类型

普通的函数如果是不同的类型,那么只能它的函数原型不同,而函数对象可以通过传递不同的模板参数来生成不同的类型,尽管它们的原型都相同。

3. 通常情况下,函数对象的效率更高

模板在编译时定义了更多的细节,相对于普通函数更容易实现为内联函数。

例子:

#include <algorithm>

#include <iostream>

#include <vector>

#include <cstdlib>

using namespace std;

bool is_prime(int number)

{

//ignore the sign

number = abs(number);

//0 and 1 are prime numbers

if (0 == number || 1 == number)

return true;

//find divisor that divides without a reminder

int divisor;

for (divisor = number / 2; 0 != number % divisor; --divisor)

{

//nothing

}

return (1 == divisor);

}

template<class InputIterator, class OutputIterator, class Predicate>

void copy_if(InputIterator first, InputIterator last, OutputIterator begin, Predicate p)

{

while(first != last)

{

if (p(*first))

*(begin++) = *first;

++first;

}

}

template<class T>

class Greater

{

public:

Greater(T value_)

:_value(value_)

{

//empty

}

bool operator()(T in_) const

{

return (in_ > _value);

}

private:

T _value;

};

int main()

{

//prepare the elements

vector<int> ivec;

for (int i = 0; i <= 30; ++i)

{

ivec.push_back(i);

}

//search for prime elements

vector<int> primes;

copy_if(ivec.begin(), ivec.end(), back_inserter(primes), is_prime);

cout << "Primes:" << endl;

copy(primes.begin(), primes.end(), ostream_iterator<int>(cout, " "));

cout << endl;

//output the primes bigger than 5

cout << "Primes bigger than 5:" << endl;

copy_if(primes.begin(), primes.end(), ostream_iterator<int>(cout, " "), Greater<int>(5));

cout << endl;

getchar();

return 0;

}

输出:

Primes:

0 1 2 3 5 7 11 13 17 19 23 29

Primes bigger than 5:

7 11 13 17 19 23 29

5.9.2 预定义函数对象

STL提供了许多预定义的函数对象支持基本的操作,例如:set<int>的确实比较函数less<int> 以及前面例子中的Greater,也有对应的greater<T>,还有作为取反操作的negate<T>,乘法运算的mutiplies<T>

例子:

#include <iostream>

#include <set>

#include <deque>

#include <algorithm>

using namespace std;

template<class Container>

void print(const Container& c, const char* promption)

{

cout << promption << endl;

copy(c.begin(), c.end(), ostream_iterator<Container::value_type>(cout, " "));

cout << endl;

}

int main()

{

set<int, greater<int> > iset;

deque<int> ide;

//prepare elements

for (int i = 1; i < 10; ++i)

{

iset.insert(i);

}

print(iset, "orignal set:");

//transform all elements to ide by multiplying 10

transform(iset.begin(), iset.end(),

back_inserter(ide), bind2nd(multiplies<int>(), 10));

print(ide, "transformed:");

//replace the value 30 to 200

replace_if(ide.begin(), ide.end(),

bind2nd(equal_to<int>(), 30), 200);

print(ide, "replaced:");

getchar();

return 0;

}

输出:

orignal set:

9 8 7 6 5 4 3 2 1

transformed:

90 80 70 60 50 40 30 20 10

replaced:

90 80 70 60 50 40 200 20 10

5.10 容器元素

5.10.1 容器元素的要求

容器元素必须满足以下条件:

1. 元素是可拷贝的,容器会在插入元素时创建元素的拷贝,因此元素的拷贝应该是高效的;

2. 元素是可通过复制操作符复制的;

3. 元素是可以被析构的,且析构函数应不抛出异常;

这些条件是所有容器通用的,此外一些特别的容器还有一些特别的需求:

1. 顺序容器的元素必须有缺省构造函数;

2. 很多操作需要 == 操作符;

3. 对于关联容器,作为排序条件操作必须要有,缺省是 <,由less<> 调用;

5.11 STL中的错误和异常

5.11.1 错误处理

STL的设计目标是更高的效率而不是安全性,因此STL没有引入更多的错误检查,而是由程序员来保证这一点。

5.11.2 异常处理

STL几乎不会因逻辑错误而抛出异常,标准唯一指出一个函数会抛出异常:at(),除此之外,则是标准C++的异常,如bad_alloc

C++标准库保证:不会在异常发生时泄露资源或违反容器的不变性。

基于节点(node)的容器(如:listmapset)在很多情况下(除开 removeremove_ifmergesortunique)能保证操作的原子性。

分享到:
评论

相关推荐

    C++ Standard template Library英文版和Effective STL中文版

    C++ Standard Template Library (STL) 是C++编程语言中不可或缺的一部分,它提供了一组高效、可重用的容器、迭代器、算法和函数对象。STL的核心思想是泛型编程,即通过模板来实现代码的复用,使得开发者可以处理不同...

    Visual C++程序设计学习笔记

    《Visual C++程序设计学习笔记》是一份深入探讨VC++编程技术的综合资料,涵盖了从基础知识到实际系统开发的广泛内容。Visual C++是Microsoft公司推出的一种强大的集成开发环境,它集成了C++编译器、调试器以及MFC...

    Visual C++程序设计学习笔记.rar

    《Visual C++程序设计学习笔记》是一份深入探讨C++编程在Microsoft Visual Studio环境下的实践指南。这份笔记涵盖了从基础知识到高级技术的广泛内容,旨在帮助读者熟练掌握Visual C++的使用,提升软件开发能力。 一...

    王道C++46期学习笔记记录.zip

    《王道C++46期学习笔记记录》是一份详细且深入的C++学习资源,旨在帮助编程初学者以及有经验的开发者进一步提升C++技能。C++是一种强大的、通用的编程语言,以其面向对象的特性、高效性能和丰富的库支持而闻名。这46...

    c++ -- stl 学习笔记

    STL(Standard Template Library,标准模板库)是C++编程语言中的一个重要组成部分,它提供了高效且灵活的数据结构和算法。这篇学习笔记将深入探讨STL的核心概念、主要组件以及其在实际编程中的应用。 首先,STL的...

    C++程序设计学习笔记

    《C++程序设计学习笔记》是一份深入探讨C++编程技术的资料,旨在帮助学习者掌握C++语言的核心概念和编程技巧。这份笔记基于C++程序设计特别版,集成了作者在学习过程中的精华理解和实践心得,对于初学者和有一定经验...

    C++学习笔记经典(与C比较)

    《C++学习笔记经典(与C比较)》这份资料应该会详细讲解这些知识点,并通过实例来帮助读者深入理解C++与C的差异,以及如何在实际编程中应用C++的特性和功能。这份资料可能会涵盖基本语法、类和对象、模板、STL的使用...

    C++STL学习笔记.pdf

    C++ Standard Template Library(STL)是C++编程语言的一个重要组件,它提供了一系列通用的数据结构和算法模板,使程序员能够以一种标准化和高效的方式处理数据。STL的主要组成部分包括容器(containers)、迭代器...

    C++基础学习笔记.pdf

    - **STL(Standard Template Library)**:深入理解容器、迭代器、算法的使用,以及自定义比较函数和迭代器适配器。 在学习过程中,不断实践和编写代码是巩固知识的关键。通过编写小程序、解决实际问题来加深对C++...

    达内学生的C++学习笔记

    《达内学生C++学习笔记》是一份专为初学者设计的C++教程,旨在提供清晰易懂、逐步深入的学习路径。这份笔记涵盖了C++语言的基础到进阶内容,是学习C++的理想辅助资料。 首先,C++是一种静态类型的、编译式的、通用...

    C++学习笔记.chm

    5. **STL(Standard Template Library)**:C++的标准模板库提供了容器(如vector、list、map)、迭代器、算法和函数对象,是C++编程中不可或缺的一部分。理解并熟练使用STL能提升编程效率和代码质量。 6. **异常...

    C++ primer学习笔记一

    本篇学习笔记主要涵盖了前三章的内容,重点关注STL(Standard Template Library,标准模板库)中的容器、特别是vector的使用,以及迭代器的概念。接下来我们将详细探讨这些知识点。 首先,STL是一个强大的工具集,...

    C++笔记.rar C++笔记.rar

    5. **STL(Standard Template Library)**:STL是C++的标准库,包含容器(如vector、list、set等)、迭代器、算法和函数对象,为程序员提供了高效的数据结构和算法。 6. **异常处理**:C++提供了异常处理机制,通过...

    C++&C学习笔记

    10. **STL(Standard Template Library)**:STL是一组通用的C++模板类和函数,包括容器、迭代器、算法和函数对象,它极大地提高了代码的效率和可读性。 11. **I/O流**:C++的I/O流库使得输入输出操作更加直观和...

    C++ SLS 学习笔记

    C++ SLS(Standard Library Style Guidelines)是一组用于编写C++标准库的编码规范,旨在提供高质量、统一的代码风格。这些指南对于任何参与C++编程,尤其是进行课程设计或大型项目开发的人来说都是极其重要的。以下...

    C++学习笔记......

    本学习笔记将深入探讨C++的基础、核心概念以及高级特性,帮助读者从初学者到熟练掌握C++。 一、C++基础 C++的基础包括基本语法、数据类型、变量、运算符、流程控制(如if语句、switch语句、for循环、while循环)和...

    C & C++学习笔记集合

    这个“C & C++学习笔记集合”显然是一份综合性的资源,旨在帮助学习者深入理解和掌握这两种语言。 C 语言是基础,它的语法简洁明了,对内存管理有直接的控制,是理解计算机底层工作原理的良好起点。C 语言的核心...

    c++学习总结,在学习c++时做的一些笔记

    6. **STL(Standard Template Library)标准库**:C++的STL包含容器(如vector、list、set等)、迭代器、算法和函数对象。熟练使用STL可以提高代码效率,简化编程任务。 7. **异常处理**:C++的异常处理机制允许...

    达内C-C++基础学习笔记

    12. **STL(Standard Template Library)**:STL是C++标准库的一部分,包含了容器(如vector、list、map等)、算法和迭代器,极大地提高了编程效率。 学习C-C++的基础,不仅需要理解和掌握上述知识点,还需要通过...

    C++自己学习的笔记和心得

    2. **类模板**:类模板可以生成处理不同类型数据的类,提供了泛型数据结构和算法,如STL(Standard Template Library)中的容器(vector、list、set等)和算法(sort、find等)。 【异常处理】 C++提供了一种处理...

Global site tag (gtag.js) - Google Analytics