第16章 string类和标准模板库
16.1 string类
string类是由头文件string支持的
头文件string.h和cstring支持对C风格字符串进行操作的C库字符串函数,但不支持string类。
16.1.1 构造字符串
string实际上是模板具体化basic_string的一个typedef,同时省略了与内存管理相关的参数。
string类将string::npos定义为字符串的最大长度。
string类的构造函数
构造函数 | 描述 |
---|---|
string(const char *s) | 将string对象初始化为s指向的C字符串 |
string(size_type n, char c) | 创建一个包含n个元素的string对象,其中每个元素都被初始化为字符c |
string(const string & str) | 将一个string对象初始化string对象str(复制构造函数) |
string() | 创建一个默认的string对象,长度为0(默认构造函数) |
string(const char *s, size_type n) | 将string对象初始化为C字符串的前n个字符,即使超过了C字符串结尾 |
template<class Iter>string(Iter begin, Iter end) | 将string对象初始化为区间[begin,end]内的字符 |
string(const string & str, string size_type pos = 0, size_type n = npos) | 将一个string对象初始化为对象str中从位置pos开始到结尾的字符 |
string(string && str) noexcept | 这是C++11新增的,它将一个string对象初始化为string对象str,并可能修改str(移动构造函数) |
string(initializer_list<char> il) | 这是C++11新增的,它将一个string对象初始化为初始化列表il中的字符:string piano_man = {‘L’, ‘i’, ‘s’, ‘z’, ‘t’); |
- string重载了+=运算符,它将一个字符串附加到另一个字符电的后面;
- string重载了=运算符用于将string对象、C风格字符串或char值赋给string对象;
- string重载了<<运算符用于显示string对象;
- string重载了[]运算符用于访问字符串中的各个字符。
- string重载+运算符将其两个操作数组合成一个string对象,第二个操作数可以是string对象、C-风格字符串或char值。
16.1.2 string类输入
C风格字符串:
char info[100];
cin >> info; // read a word
cin.getline(info, 100); // read a line, discard \n
cin.getline(indo, 100, ':'); // read up to :, discard :
cin.get(info, 100) // read a line, leave \n in queue
string对象:
string stuff;
cin >> stuff; // read a word
getline(cin, stuff); // read a line, discard \n
getline(cin, stuff, ':'); // read up to :, discard :
string版本的getline()将自动调整目标string对象的大小,使之刚好能够存储输入的字符。
string版本的getline()在遇到一下三种情况时停止读取字符:
- 到达文件为,在这种情况下,输入流的eofbit将被设置,这意味着方法fail()和eof()都将返回true
- 遇到分界字符(默认为\n),在这种情况下,将把分界字符从输入流中删除,但不存储它
- 读取的字符数达到最大允许值,将设置输入流的failbit,这意味着方法fail()将返回true
16.1.3 使用字符串
string 类对全部6个关系运算符都进行了重载。
能够将string对象与另一个string对象、C-风格字符串进行比较,并能够将C-风格字符串与string对象进行比较。
size()和length()成员函数都返回字符串中的字符数。
重载的find()方法
-
size_type find(const string & str, size_type pos = 0) const
:从字符串的pos位置开始,查找子字符串str。如果找到,则返回该子字符串首次出现时其首字符的索引;否则,返回string::npos -
size_type find(const char *s, size_type pos = 0) const
:从字符串的pos位置开始,查找子字符串s。如果找到,则返回该子字符串首次出现时,其首字符的索引;否则,返回string::npos -
size_type find(const char*S, size_type pos = 0, size_type n)
:从字符串的pos位置开始,查找s的前n个字符组成的子字符串。如果找到,则返回该子字符串首次出现时其首字符的索引;否则,返回string::npos -
size_type find(char ch, size_type pos = 0) const
:从字符串的pos位置开始,查找字符ch。如果找到,则返回该字符首次出现的位置:否则,返回string::npos -
rfind()方法查找子字符串或字符最后一次出现的位置:
-
find_first_of()方法在字符串中查找参数中任何一个字符首次出现的位置。
-
find_last_of()方法在字符串中查找参数中任何一个字符最后一次出现的位置。
-
find_first_not_of()方法在字符串中查找第一个不包含在参数中的字符
16.1.4 string还提供了哪些功能
capacity()返回当前分配给字符串的内存块的大小
reserve()方法让您能够请求内存块的最小长度
c_str()方法返回一个指向 C-风格字符串的指针
16.1.5字符串种类
string库实际上是基于一个模板类的:
temlate <class charT, class traits = char_traits<charT>, class Allocator = allocator<charT>>
basic_string {...};
//traits类描述关于选定字符类型的特定情况;Allocator是一个管理内存分配的类
模板basic_string有4个具体化,每个具体化都有一个 typedef 名称:
typedef basic_string<char> string;
typedef basic_string<wchar_t> wstring;
typedef basic_string<char16_t> u16string; // C++11
typedef basic_string<char32_t> u32string; // C++11
16.2 智能指针
16.2.1 使用智能指针
三个智能指针模板(auto_ptr,unique_ptr和shared_ptr,头文件:memory)都定义了类似指针的对象,可以将new获得的地址赋给这种对象。当智能指针过期时,其析构函数将使用delete来释放内存。
unique_ptr<double> pdu (new double);
所有智能指针类都一个explicit构造函数,该构造函数将指针作为参数。
16.2.2有关智能指针的注意事项
auto_ptr对于特定的对象,只能有一个智能指针可拥有它。让赋值操作转让所有权。
使用shared_ptr可以保证一个指针不被delete两次。
16.2.3 unique_ptr为何优于auto_ptr
程序试图将一个unique_ptr赋给另一个时,如果源unique_ptr是个临时右值,编译器允许这样做;如果源unique ptr将存在一段时间,编译器将禁止这样做:
std::move()函数是将对象的状态或者所有权从一个对象转移到另一个对象,只是转移,没有内存的搬迁或者内存拷贝。可以用于将一个unique_ptr赋给另一个。
unique_ptr使用new[]和delete[]的版本:std::unique_ptr<double []> pda (new double (5));
16.2.4 选择智能指针
模板shared_ptr包含一个显式构造函数,可用于将右值unique_ptr转换为shared_ptr,shared_ptr将接管原来归unique_ptr所有的对象。
16.3 STL
16.3.1 vector模板类
矢量(vector)对应数组。
头文件vector中定义了一个vector模板,可以创建vector对象,可以用初始化参数来指出需要多少矢量,将一个vector对象赋给另一个对象,使用[]操作符访问vector元素;
16.3.2 可对矢量执行的操作
STL 容器提供了一些基本方法:
- size():返回容器中元素数目
- swap():交换两个容器的内容
- begin():返回一个指向容器中第一个元素的迭代器
- end():返回一个超过容器尾的迭代器
迭代器的类型是一个名为iterator的typedef,其作用域为整个类。
vector特有函数:
- push_back()将元素添加到矢量末尾。
- erase()方法删除矢量中给定区间的元素。它接受两个选代器参数;
- inser()方法插入元素。第一个参数指定了新元素的插入位置,第二个和第三个选代器参数定义了被插入区间,该区间通常是另一个容器对象的一部分。
16.3.3 对矢量可执行的其他操作
代表性的STL函数:头文件(algorithm)
- for_each():前两个是定义容器中区间的迭代器,最后一个是函数指针(函数对象)。该函数指针参数为元素的引用。将被指向的函数应用于容器区间中的各个元素,被指向的函数不能修改容器元素的值。
- random_shuff():接受两个指定区间的迭代器参数,并随机排列该区间中的元素(要求容器类允许随机访问)
- sort():第一个版本接受两个定义区间的迭代器参数,使用为存储容器中元素的类型元素定义<操作符,进行升序排序。(要求容器类允许随机访问)
- sort():前两个是指定区间地迭代器,最后一个参数是指向要使用的函数的指针(函数对象)。(要求容器类允许随机访问)。函数指针的参数为两个要比较的元素类型引用,返回值为bool,false表示两个参数的顺序不正确。
泛型编程
16.4.1 为何使用迭代器
C++将operator++作为前级版本,将operator++(int)作为后缀版本。
迭代器是一个广义指针。迭代器都提供解引用(*)、递增(++)操作、(==)相等、(!=)不等。其次,每个容器类都有一个超尾标记,当选代器递增到超越容器的最后一个值后,这个值将被赋给选代器。
每个容器类都有begin()和end()方法,它们分别返回一个指向容器的第一个元素和超尾位置的选代器。
16.4.2 迭代器类型
STL定义了5种迭代器入迭代器、输出迭代器、正向迭代器、双向迭代器、随机访问迭代器。
输入迭代器:
- 需要输入选代器的算法将不会修改容器中的值。
- 基于输入迭代器的任何算法都应当是单通行的,不依赖于前一次遍历时的迭代器值,也不依赖于本次遍历汇总前面的迭代器值。
- 输入迭代器是单向迭代器,可以递增,但不能倒退。
输出迭代器
- 解除引用让程序能修改容器值,而不能读取。
- 输出迭代器是单向迭代器。
正向迭代器
- 正向选代器只使用++运算符来遍历容器,所以它每次沿容器向前移动一个元素。
- 它总是按相同的顺序遍历一系列值。
- 将正向迭代器递增后,仍然可以对前面的选代器值解除引用。
- 正向选代器既可以使得能够读取和修改数据。
双向迭代器
- 双向迭代器具有正向迭代器的所有特性,同时支持两种(前缀和后缀)递减运算符。
随机访问迭代器
- 随机访问选代器具有双向选代器的所有特性。
- T表示被指向的类型,a和b都是选代器值,n为整数,r为随机选代器变量或引用。
- 支持a + n、n + a、a - n、r += n、r - = n、a[n]、b - a、a < b、a > b、a >= b、a <= b
16.4.4 概念、改进和模型
指针满足所有的选代器要求。
copy()可以将数据从一个容器复制到另一个容器中。
前两个选代器参数表示要复制的范围,最后一个选代器参数表示要将第一个元素复制到什么位置。
STL为输出流迭代器提供了ostream_iterator模板;包含头文件iterator。
#include <iterator>
...
ostream_iterator<int, char> out_iter(cout, "");
第一个模板参数指出被发送给输出流的数据类型
第二个模板参数指出输出流使用的字符类型
构造函数的第一个参数(cout)指出了要使用输出流,也可用于文件的输出流。
构造函数的第二个参数是在给发送输出流的每个数据项后显示的分隔符。
iterator头文件还定义了一个istream_iterator模板,使istream输入可用作选代器接口。它是一个输入代器概念的模型,可以使用两个istream_iterator对象来定义copy()的输入范围:
copy (istream_iterator<int, char>(cin), istream_iterator<int, char>(), dice.begin());
头文件iterator还提供了其他一些专用的预定义迭代器类型:
- reverse_iterator: 执行递增操作将导致递减
- back_insert_iterator:将元素插入到容器尾部,需要快速插入实现
- front_insert_iterator:将元素插入到容器前端,需要快速插入实现
- insert_iterator:将元素插入到构造函数的参数指定位置前面
这些选代器将容器类型作为模板参数,将实际的容器标识符作为构造函数参数。对于insert_iterator,还需一个指示插入位置的构造函数参数。
vector类有一个名为rbegin()的成员函数和一个名为rend()的成员函数,前者返回一个指向超尾的反向选代器,后者返回一个指向第一个元素的反向选代器。
16.4.5 容器种类
类型必须是可复制构造的和可赋值的。
一些基本的容器特征
其中X表示容器类型,a和b表示类型为X的值,r表示类型为X&的值,u表示类型为X的标识符
表达式 | 返回类型 | 说明 | 复杂度 |
---|---|---|---|
X::iterator | 指向T的迭代器类型 | 满足正向迭代器要求的任何迭代器 | 编译时间 |
X::value_type | T | T的类型 | 编译时间 |
X u; | 创建一个名为u的空容器 | 固定 | |
X(); | 创建一个匿名的空容器 | 固定 | |
X u(a); | 调用复制构造函数后u==a | 线性 | |
X u = a; | 作用同X u(a); | 线性 | |
r = a; | X& | 调用赋值运算符后r==a | 线性 |
(&a)->~X(); | void | 对容器中每个元素应用析构函数 | 线性 |
a.begin() | 迭代器 | 返回指向容器第一个元素的迭代器 | 固定 |
a.end() | 迭代器 | 返回超尾值迭代器 | 固定 |
a.size() | 无符号整型 | 返回元素个数,等价于a.end()-a.begin() | 固定 |
a.swap(b) | void | 交换a和b的内容 | 固定 |
a == b | 可转换为bool | 如果a和b的长度相同,且a中每个元素都等于(==为真)b中相应的元素,则为帧 | 线性 |
a != b | 可转换bool | 返回!(a==b) | 线性 |
C++11新增的容器要求
表达式 | 返回类型 | 说明 | 复杂度 |
---|---|---|---|
X u(rv); | 调用移动构造函数后,u的值与rv的原始值相同 | 线性 | |
X u = rv; | 作用同X u(rv); | ||
a = rv; | X& | 调用移动赋值运算符后,u的值与rv的原始值相同 | 线性 |
a.cbegin() | const_iterator | 返回指向容器第一个元素的const迭代器 | 固定 |
a.cend | const_iterator | 返回超尾值const迭代器 | 固定 |
序列:
序列概念增加了迭代器至少是正向迭代器这样的要求。
序列还要求其元素按严格的线性顺序排列。
queue:让您能够在队尾添加元素;在队首删除元素。
deque:双端队列允许在两端添加和删除元素。deque头文件。
list:双向链表,list头文件。
序列的要求
t表示类型为T的值,n表示整数,p、q、i、j表示选代器。
表达式 | 返回类型 | 说明 |
---|---|---|
X a(n, t); | 声明一个名为a的由n个t值组成的序列 | |
X(n, t) | 创建一个由n个t值组成的匿名序列 | |
X a(i, j) | 声明一个名为a的序列,并将其初始化为区间[i, j)的内容 | |
X(i, j) | 创建一个匿名序列,并将其初始化为区间[i, j)的内容将t插入到p的前面 | |
a.insert(p, t) | 迭代器 | t插入p的前面 |
a.insert(p, n, t) | void | 将n个t插入到p的前面 |
a.insert(p, i, j) | void | 将区间[i, j)中的元素插入到p的前面 |
a.erase§ | 迭代器 | 删除p指向的元素 |
a.erase(p, q) | 迭代器 | 删除区间[p, q)中的元素 |
a.clear() | void | 删除全部元素 |
序列的可选要求
表达式 | 返回类型 | 含义 | 容器 |
---|---|---|---|
a.front() | T& | *a.begin() | vector、list、deque |
a.back() | T& | *–a.end() | vector、list、deque |
a.push_front(t) | void | a.insert(a.begin(), t) | list、deque |
a.push_back(t) | void | a.insert(a.end(), t) | vector、list、deque |
a.pop_front(t) | void | a.erase(a.begin()) | list、deque |
a.pop_back(t) | void | a.erase(–a.end()) | vector、list、deque |
a[n] | T& | *(a.begin() + n) | list、deque |
a.at(t) | T& | *(a.begin() + n) | list、deque |
a.at(n)将执行边界检查,并引发out_of_range异常。
list成员函数
函数 | 说明 |
---|---|
void merge(list<T, Alloc> &x) | 将链表x与调用链表合并。两个链表必须已经排序。合并后的经过排序的链表保存在调用链表中,x为空。这个函数的复杂度为线性时间 |
void remove(const T &val) | 从链表中删除val的所有实例。这个函数的复杂度为线性时间 |
void sort() | 使用<运算符对链表进行排序:N个元素的复杂度为NlogN |
void splice(iterator pos, list<T, Alloc> x) | 将链表x的内容插入到pos的前面,x将为空。这个函数的的复杂度为固定时间 |
void unique() | 将连续的相同元素压缩为单个元素。这个函数的复杂度为线性时间 |
splice()将原始区间移到目标地址。splice()方法执行后,选代器仍有效。
sort(),merge()和unique()方法还各自拥有接受另一个参数的版本,该参数用于指定用来比较元素的函数。
remove()方法也有一个接受另一个参数的版本remove_if(),该参数用于指定用来确定是否删除元素的函数。
forward_list,它实现了单链表。
forward_list是不可反转的容器。
queue模板类(在头文件queue(以前为queue.h)中声明)是一个适配器类。
不允许随机访问队列元素,不允许遍历队列。
queue的操作
- bool empty():如果队列为空,则返回true;否则返回false
- const size_type size() const:返回队列中元素的数目
- T &front():返回指向队首元素的引用
- T &back():返回指向队尾元素的引用
- void push(const T &x):在队尾插入x
- void pop():删除队首元素
priority_queue模板类(在queue头文件中声明)是另一个适配器类,它支持的操作与queue相同。在priority_queue中,最大的元素被移到队首。
stack(在头文件stack以前为stack.h中声明)也是一个适配器类。
不允许随机访问栈元素,甚至不允许遍历栈。
stack的操作:
- bool empty():如果栈为空,则返回true;否则返回false
- const size_type size() const:返回栈中的元素数目
- T &top():返回指向栈顶元素的引用
- void push(const T &x):在栈顶部插入x
- void pop():删除栈顶元素
模板类array是否头文件array中定义的。
array没有定义调整容器大小的操作
16.4.4,关联容器
关联容器将值与键关联在一起,并使用键来查找值。
表达式X::value_type通常指出了存储在容器中的值类型。
关联容器也允许插入新元素,但不能指定元素的插入位置。
关联容器通常是使用某种树实现的。
4种关联容器:set、multiset、map、multimap。
前两种是在头文件set(以前分别为set和multiset.h)中定义的,而后两种是在头文件map(以前分别为map.h和multimap.h)中定义的。
set:
- set其值类型与键相同,键是唯一的。
- 值就是键
- 可反转,可排序
- 第二个模板参数是可选的,可用于指示用来对键进行排序的比较函数或对象。
- set也有一个将选代器区间作为参数的构造函数
- lower_bound()将键作为参数并返回一个选代器,该选代器指向集合中第一个不小于键参数的成员。
- upper_bound()将键作为参数,并返回一个选代器,该选代器指向集合中第一个大于键参数的成员。
STL函数:
- set_union()函数接受5个迭代器参数。前两个选代器定义了第一个集合的区间,接下来的两个定义了第二个集合区间,最后一个选代器是输出选代器,指出将结果集合复制到什么位置。并集。覆盖容器中已有的数据。
- 函数set_intersection()和 set_difference()分别查找交集和获得两个集合的差,它们的接口与set_union()相同。
multiset
- 类似于set,只是可能有多个值的键相同。
map
- 值与键的类型不同,键是唯一的,每个键只对应一个值。
multimap
- 与map相似,可反转的、经过排序的关联容器,但键和值的类型不同,只是一个键可以与多个值相关联。
- 基本的multimap声明使用模板参数指定键的类型和存储的值类型。第3个模板参数是可选的,指出用于对键进行排序的比较函数或对象。在默认情况下,将使用模板less<>。
- STL使用模板类pair<class T,class U>将这两种值存储到一个对象中。如果keytype是键类型,而datatype是存储的数据类型,则值类型为pair<const keytype,datatype>。
- 对于pair对象,可以使用first和second成员来访问其两个部分
- count()接受键作为参数,并返回具有该键的元素数目。
- lower_bound()和upper_bound()将键作为参数,且工作原理与处理set时相同。
- equal_range()用键作为参数,且返回两个选代器,它们表示的区间与该键匹配。为返回两个值,该方法将它们封装在一个pair对象中,这里pair的两个模板参数都是选代器。
16.5 面数对象
函数符是可以以函数方式与()结合使用的任意对象。这包括函数名、指向函数的指针和重载了()运算符的类对象。
函数符的概念:
- 生成器是不用参数就可以调用的函数符;
- 一元函数是用一个参数调用的函数符;
- 二元函数是用两个参数可以调用的函数符;
- 返回bool值的一元函数是谓词;
- 返回bool值的二元函数是二元谓词
可以使用C++11的初始化列表来初始化容器:`list yadayada = {50, 100, 90, 180,60, 210, 415, 88, 188, 20F};
16.5.2 预定义的函数符
transform()它存两个版本。第一个版本接受4个参数,前两个参数是指定容器区间的选代器(现在您应该已熟悉了这种方法),第3个参数是指定将结果复制到哪里的选代器,最后一个参数是一个函数符,它被应用于区间中的每个元素,生成结果中的新元素。
第2种版本使用一个接受两个参数的函数,并将该函数用于两个区间中元素。它用另一个参数(即第3个)标识第二个区间的起始位置。
例:
double add(double x, double y)
{
return x + y;
}
transform(gr8.begin(), gr8.end(), m8.begin(), out, add);
头文件functional(以前为function.h)定义了多个模板类函数对象,其中包括plus<>()。
运算符和相应的函数符:
- +:plus
- -:minus
- *:multiplies
- /:divides
- %:modulus
- -:negate
- ==:equal_to
- !=:not_equal_to
- >:greater
- <:less
- >=:greater_equal
- <=:less_equal
- &&:logical_and
- ||:logical_or
- !:logical-not
16.5.3 自适应函数符和函数适配器
以上的预定义函数符都是自适应的。
使函数符成为自适应的原因是,它携带了标识参数类型和返回类型的typedef成员。这些成员分别是result_type,first_argument_type和second_argument_type。
例如,plus对象的返回类型被标识为plus::result_type,这是int的typedef。
STL使用binderlst和binder2nd类自动完成这一过程,它们将自适应二元函数转换为自适应一元函数。
假设有一个自适应二元函数对象f2(),则可以创建一个binderlst对象,该对象与一个将被用作f2()的第一个参数的特定值(val)相关联:binderist(f2, val) fl;
STL提供了函数bind1st(),可以问其提供用于构建binderlst对象的函数名称和值,它将返回一个这种类型的对象。
binder2nd类与此类似,只是将常数赋给第二个参数,而不是第一个参数。它有一个名为bind2nd的助手函数,该函数的工作方式类似于bindIst。
16.6 算法
16.6.1 算法组STL
将算法库分成4组:
- 非修改式序列操作
- 修改式序列操作
- 排序和相关操作
- 通用数字运算。
前3组在头文件algorithm(以前为algo.h)中描述。
第4组在头文件numeric(以前为algol.h)中描述。
16.6.2 算法的通用特征
有些算法有两个版本:就地版本和复制版本。STL的约定是,复制版本的名称将以_copy结尾。复制版本将接受一个额外的输出选代器参数,该参数指定结果的放置位置。
对于复制算法,返回一个选代器,该选代器指向复制的最后一个值后面的一个位置。
有些函数有以_if结尾的版本,即根据将函数应用于容器元素得到的结果来执行操作。
16.6.3 STL和string类
string类它包含begin()、end()、rbegin()和rend()。
next_permutation()算法将区间内容转换为下一种排列方式。对于字符串,排列按照字母递增的顺序进行。如果成功,该算法返回true;如果区间已经处于最后的序列中,则该算法返回false。
16.6.4 函数和容器方法
由于remove()函数不是成员,因此不能调整链表的长度。它将没被删除的元素放在链表的开始位置,并返回一个指向新的超尾值的选代器。这样,便可以用该选代器来修改容器的长度。
可以使用链表的erase()方法来删除一个区间,该区间描述了链表中不再需要的部分。
16.6.5 使用 STL
可以使用count()函数。它将一个区间和一个值作为参数,并返回这个值在区间中出现的次数。
map类有一个有趣的特征:可以用数组表示法(将键用作索引)来访问存储的值。
如果键无效,则对应的值将为0。
16.7 其他库
头文件complex为复数提供了类模板complex,包含用于float、long和long double的具体化。这个类提供了标准的复数运算及能够处理复数的标准函数。
C++11新增的头文件random提供了更多的随机数功能。
第14章介绍了头文件valarray提供的模板类valarray。这个类模板被设计成用于表示数值数组,支持各种数值数组操作。
16.7.1 vector、valarray和array
vector模板类是一个容器类和算法系统的一部分,它支持面向容器的操作,如排序、插入、重新排列、搜索、将数据转移到其他容器中等。
而valarray类模板是面向数值计算的,不是STL的一部分。它没有push_back()和insert()方法,但为很多数学运算提供了一个简单、直观的接口。valarray类重载了所有算术运算符,使其能够用于valarray对象。
array是为替代内置数组而设计的,它通过提供更好、更安全的接口,让数组更紧凑,效率更高。Array表示长度固定的数组,因此不支持push_back()和insert(),但提供了多个STL方法,包括begin()、end()、rbegin()和rend(),这使得很容易将STL算法用于array对象。
假设您要计算数组中每个元素的自然对数,并将计算结果存储到另一个数组的相应元素中,STL方法如下:
transform(ved1.begin(), ved1.end(), ved3.begin, log);
valarray类重载了这种数学函数,使之接受一个valarray参数,并返回一个valarray对象,因此您可以这样做:
vad3 = Iog(vad1); //1og() overloaded
也可以使用apply()方法,该方法也适用于非重载函数:
vad3 = vad1.apply(log);
方法apply()不修改调用对象,而是返回一个包含结果的新对象。
valarray类还提供了方法sum()(计算valarray对象中所有元素的和)、size()(返回元素数)、max()(返回最大的元素值)、min()(返回最小的元素值)。
C++11提供了接受valarray对象作为参数的模板函数begin()和end()。
slice类对象可用作数组索引,在这种情况下,它表的不是一个值而是一组值。slice对象被初始化为三个整数值:起始索引、索引数和跨距。起始索引是第一个被选中的元素的索引,索引数指出要选择多少个元素,跨距表示元素之间的间隔。
16.7.2 模板initializer_list(C++11)
容器类现在包含将initializer_list作为参数的构造函数。使得能够:
std::vector<double> payments {45.99, 39.23, 19.95, 89.01};
如果类有接受initializer_list作为参数的构造函数,则使用语法{}将调用该构造函数。
列表不能进行隐式的窄化转换。
16.7.3 使用initializer_list
包含头文件initializer_list。
包含成员函数begin()和end(),您可使用这些函数来访问列表元素。
包含成员函数size(),该函数返回元素数。