C++ primer plus 第16章 string类和标准模板库

templatestring(Iter begin,Iter end);
//构造函数将使用begin和end指向的位置之间的值,对string对象初始化。[begin,end)意味着包含begin,但不包含end在内的区间,end指向被使用的最后一个值后面的一个位置。

//假设要用构造函数将对象初始化为另一个string对象(five)的一部分
string seven(five+6,five+10);//five不是指针,所以five+6没有意义
string seven(&five[6],&five[10]);//five[6]是一个值,&five[6]是一个地址,可以被用作改构造函数的参数

1.C++11新增的构造函数:

构造函数string(string &&str)类似于复制构造函数,导致新创建的string为str的副本,但与复制构造函数不同的是,它不保证将str视为const。这种构造函数被称为移动构造函数

2.string输入

C-风格字符串,有3种:

char info[100];
cin>>info;
cin.getline(info,100);
cin.get(info,100);

对于string对象,有2种:

string stuff;
cin>>stuff;
getline(cin,stuff);

string版本可以自动调整目标string的大小,但存在限制:(1)string对象的最大允许长度,由常量string::npos指定,这通常是最大的unsigned int值,对于普通的交互式输入,不会带来实际限制,但如果试图将整个文件的内容读取到单个string对象中,这可能成为限制因素。(2)程序可以使用的内存量。

string版本的getline()函数从输入中读取字符,并将其存储到目标string中,直到发生下列三种情况之一:

(1)到达文件尾,在这种情况下,输入流的eofbit将被设置,方法fail()和eof()都将返回true;

(2)遇到分界字符(默认为\n),在这种情况下,将把分界字符从输入流中删除,但不存储它;

(3)读取的字符数达到最大允许值(string::npos和可供分配的内存字节数中较小的一个),在这种情况下,将设置输入流的failbit,这意味着方法fail()将返回true。

3.智能指针模板类

可以帮助管理动态内存分配的智能指针模板:auto_ptr、unique_ptr和shared_ptr都定义了类似指针的对象,可以将new获得(直接或间接)的地址赋给这种对象。当智能指针过期时,其析构函数将使用delete来释放内存。因此,如果将new返回的地址赋给这些对象,将无需记住稍后释放这些内存:智能指针过期时,这些内存将自动被释放。

要创建智能指针对象,必须包含头文件memory,然后使用通常的模板语法来实例化所需类型的指针。

有关智能指针的注意事项:为何摒弃auto_ptr?

auto_ptr ps(new string("I regined lonely as a cloud."));
auto_ptrvocation;
vocation=ps;

ps和vocation是常规指针,则两个指针将指向同一个string对象,这是不能接受的,因为程序将试图删除同一个对象两次,要避免这种问题,方法有多种:

(1)定义赋值运算符,使之执行深复制。这样两个指针将指向不同的对象,其中的一个对象是另一个对象的副本。

(2)建立所有权概念,对于特定的对象,只能有一个智能指针可以拥有它,这样只有拥有对象的智能指针的构造函数会删除该对象。然后,让赋值操作转让所有权,这就是用于auto_ptr和unique_ptr的策略,但unique_ptr的策略更严格。

(3)创建智能更高的指针,跟踪引用特定对象的智能指针数。这称为引用计数。

auto_ptr和unique_ptr会放弃对象的所有权,之后是一个空指针,再次指向或输出它时会出现错误。使用auto_ptr出现意外时,在运行阶段崩溃,使用unique_ptr出现意外时,不会等到运行阶段崩溃,在编译器就会出现错误,而使用shared_ptr就不会。

C++有一个标准库函数std::move(),能将一个unique_ptr赋给另一个。

使用new分配内存时,才能使用auto_ptr和shared_ptr,使用new[]分配内存时,不能使用它们。不使用new分配内存时,不能使用auto_ptr或shared_ptr;不使用new或new[]分配内存时,不能使用unique_ptr。

4.选择智能指针

如果程序要使用多个指向同一个对象的指针,应选择hared_ptr。很多STL算法都支持复制和赋值操作,这些操作可用于shared_ptr,但不能用于unique_ptr(编译器发出警告)和auto_ptr(行为不确定)。如果程序不需要多个指向同一个对象的指针,则可使用unique_ptr。如果函数使用new分配内存,返回指向该内存的指针,将其返回类型声明为unique_ptr是不错的选择。

5.基于范围的for循环(C++11)

基于范围的for循环是为用于STL而设计的:

double prices[5]={4.99,10.99,6.87,7.99,8.49};
for(doube x:prices)
    cout<

不同于for_each(),基于范围的for循环可以修改容器的内容,诀窍是指定一个引用参数。

void InflateReview(Review &r) {r.rating++;}//可使用如下循环对books的每个元素执行该函数:
for(auto &x:books) InflateReview(x);

STL是一种泛型编程。面向对象编程关注的是编程的数据方面,而泛型编程关注的是算法。它们之间的共同点事抽象和创建可重用代码,但它们的理念绝然不同。泛型编程旨在编写独立于数据类型的代码。在C++中,完成通用程序的工具是模板。

模板使得算法独立于存储的数据类型,而迭代器使算法独立于使用的容器类型。

C++将operator++作为前缀版本,将operator++(int)作为后缀版本;其中的参数永远不会被用到,所以不必指定其名称。

iterator& operator++()//for ++it
{
    pt=pt->p_next;
    return *this;
}
iterator operator++(int)//for it++
{
    iterator tmp=*this;
    pt=pt->p_next;
    return temp;
}

6.迭代器的类型

不同的算法对迭代器的要求不同。查找算法需要定义++运算符,以便迭代器能够遍历整个容器;它要求能够读取数据,但不要求能够写数据(它只查看数据,而并不修改数据)。而排序算法要求能够随机访问,以便能够交换两个不相邻的元素。排序算法要求能够读写数据。

STL定义了5种迭代器,并根据所需的迭代器类型对算法进行了描述。这5中迭代器分别是输入迭代器、输出迭代器、正向迭代器、双向迭代器和随机访问迭代器。输入迭代器是单向迭代器,可以递增,但不能倒退。输出迭代器是单通行、只写算法。正向迭代器既可以使得能够读取和修改数据,也可以使得只能读取数据;双向迭代器具有正向迭代器的所有特性,同时支持两种(前缀和后缀)递减运算符;随机访问迭代器具有双向迭代器的所有特性,同时添加了支持随机访问的操作(如指针增加运算)和用于对元素进行排序的关系运算符。

//正向迭代器
int *pirw;//读取和修改
const int *pir;//只读

back_insert_iterator、front_insert_iterator和insert_iterator三种插入迭代器通过将复制转换为插入,插入将添加新的元素,而不会覆盖已有的数据,并使用自动内存分配来确保能够容纳新的信息。back_insert_iterator将元素插入到容器尾部,front_insert_iterator将元素插入到容器前端,insert_iterator将元素插入到insert_iterator构造函数的参数指定的位置前面。这三种插入迭代器都是输出容器概念的模型。

7.容器种类

容器是存储其他对象的对象,被存储的对象必须是同一种类型的,它们可以是OOP意义上的对象,也可以是内置类型值。存储在容器中的数据为容器所有,这意味着当容器过期时,存储在容器中的数据也将过期。不能将任何类型的对象存储在容器中,具体的说,类型必须是可以复制构造的和可赋值的。

复制构造和复制赋值以及移动构造和移动赋值之间的差别在于:复制操作保留源对象,而移动操作可修改源对象,还可能转让所有权,而不做任何复制。如果源对象是临时的,移动操作的效率将高于常规复制。

8.序列

可以通过添加要求来改进基本的容器概念,序列是一种重要的改进。7种STL容器类型(deque、C++11新增的forward_list、list、queue、priority_queue、stack和vector)都是序列。序列增加了迭代器至少是正向迭代器这样的要求,保证了元素将按特定顺序排列。

序列还要求其元素按严格的线性顺序排列,即存在第一个元素、最后一个元素,除第一个元素和最后一个元素外,每个元素前后都分别有一个元素。数组和链表都是序列,但是分支结构不是。因为序列中的元素具有特定的顺序,因此可以执行诸如将值插入到特定位置、删除特定区间等操作。

关联容器:将值与键关联在一起,并使用键来查找值。其优点是提供了对元素的快速访问。与序列相似,关联容器也允许插入新元素,但不能指定元素的插入位置。原因是关联容器通常有用于确定数据放置位置的算法,以便能够快速检索信息。

关联容器通常是使用某种树实现的。树是一种数据结构,其根节点链接到一个或两个节点,而这些节点又链接到一个或两个节点,从而形成分支结构。像链表一样,节点使得添加或删除数据项比较简单;但相对于链表,树的查找速度更快。

STL提供了4种关联容器:set、multiset、map和multimap。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

你可能感兴趣的:(C++基础学习)