c++ primer plus 第16章string 类和标准模板库, 16.3.2 可对矢量执行的操作

c++ primer plus 第16章string 类和标准模板库, 16.3.2 可对矢量执行的操作

c++ primer plus 第16章string 类和标准模板库, 16.3.2 可对矢量执行的操作

文章目录

  • [c++ primer plus 第16章string 类和标准模板库, 16.3.2 可对矢量执行的操作](#c++ primer plus 第16章string 类和标准模板库, 16.3.2 可对矢量执行的操作)
  • [16.3.2 可对矢量执行的操作](#16.3.2 可对矢量执行的操作)
  • [程序清单16.8 vect2.cpp](#程序清单16.8 vect2.cpp)

16.3.2 可对矢量执行的操作

除分配存储空间外,vector 模板还可以完成哪些任务呢?所有的STL容器都提供了一些基本方法,其中包括 size()--返回容器中元素数目、swap()--交换两个容器的内容、begin()--返回一个指向容器中第一个元素的迭代器、end()--返回一个表示超过容器尾的迭代器。什么是迭代器?它是一个广义指针。事实上,它可以是指针,也可以是一个可对其执行类似指针的操作--如解除引用(如 operator*())和递增(如 operator++( ))--的对象。稍后将知道,通过将指针广义化为迭代器,让 STL能够为各种不同的容器类(包括那些简单指针无法处理的类)提供统一的接口。每个容器类都定义了一个合适的迭代器,该迭代器的类型是一个名为 iterator 的typedef,其作用域为整个类。例如,要为vector的double类型规范声明一个迭代器,可以这样做:

cpp 复制代码
vector<double>::iterator pd;//pd an iterator

假设 scores 是一个 vector对象:

cpp 复制代码
vector<double>scores;

则可以使用迭代器 pd 执行这样的操作:

cpp 复制代码
pd = scores.begin();//have pd point to the first element
*pd =22.3;//dereference pd and assign value to first element
++pd;//make pd point to the next element

正如您看到的,迭代器的行为就像指针。顺便说一句,还有一个C++11自动类型推断很有用的地方。例如,可以不这样做:

cpp 复制代码
vector<double>::iterator pd=scores.begin();

而这样做:

auto pd =scores.begin();//C++11 automatic type deduction回到前面的示例。什么是超过结尾(past-the-end)呢?它是一种迭代器,指向容器最后一个元素后面的那个元素。这与 C-风格字符串最后一个字符后面的空字符类似,只是空字符是一个值,而"超过结尾'是一个指向元素的指针(迭代器)。end()成员函数标识超过结尾的位置。如果将迭代器设置为容器的第一个元素,并不断地递增,则最终它将到达容器结尾,从而遍历整个容器的内容。因此,如果scores和pd的定义与前面的示例中相同,则可以用下面的代码来显示容器的内容:

cpp 复制代码
for(pd=scores.begin();pd != scores.end(); pd++)
cout << *pd << endl; 

所有容器都包含刚才讨论的那些方法。vector模板类也包含一些只有某些STL容器才有的方法。push back()是一个方便的方法,它将元素添加到矢量末尾。这样做时,它将负责内存管理,增加矢量的长度,使之能够容纳新的成员。这意味着可以编写这样的代码:

cpp 复制代码
vector<double>scores;//create an empty vector
double temp;
while(cin>>temp &&temp >=0)
scores.push back(temp);
cout <<"You entered"<<scores.size()<<" scores.\n";

每次循环都给 scores 对象增加一个元素。在编写或运行程序时,无需了解元素的数目。只要能够取得足够的内存,程序就可以根据需要增加 scores 的长度。

erase()方法删除矢量中给定区间的元素。它接受两个迭代器参数,这些参数定义了要删除的区间。了解 STL 如何使用两个迭代器来定义区间至关重要。第一个迭代器指向区间的起始处,第二个迭代器位于区间终止处的后一个位置。例如,下述代码删除第一个和第二个元素,即删除begin()和 begin()+1指向的元素(由于 vector 提供了随机访问功能,因此 vector 类迭代器定义了诸如 begin()+2等操作):

cpp 复制代码
scores.erase(scores.begin(),scores.begin()+2);

如果 it1 和 it2 是迭代器,则 STL 文档使用[p1,p2)来表示从p1到p2(不包括 p2)的区间。因此,区间[begin(),end()]将包括集合的所有内容(参见图 16.3),而区间[p1,p1)为空。[)表示法并不是 C++的组成部分,因此不能在代码中使用,而只能出现在文档中。
注意:区间[it1.it2)由迭代器 it1 和 it2 指定,其范围为 it1 到 it2(不包括 it2)。

insert()方法的功能与 erase()相反。它接受3个迭代器参数,第一个参数指定了新元素的插入位置,第二个和第三个迭代器参数定义了被插入区间,该区间通常是另一个容器对象的一部分。例如,下面的代码将矢量newv中除第一个元素外的所有元素插入到oldv矢量的第一个元素前面:

cpp 复制代码
vector<int>old v;
vector<int>new v;
old v.insert(old v.begin(),new v.begin()+ 1,new v.end());

顺便说一句,对于这种情况,拥有超尾元素是非常方便的,因为这使得在矢量尾部附加元素非常简单。

下面的代码将新元素插入到 old.end()前面,即矢量最后一个元素的后面。

cpp 复制代码
old v.insert(old v.end(),new v.begin()+ 1,new v.end());

程序清单16.8演示了 size()、begin()、end()、push back()、erase()和insert( )的用法。为简化数据处理,将程序清单16.7中的rating和title组合成了一个Review结构,并使用 FilReview()和 ShowReview()函数来输入和输出 Review 对象。

程序清单16.8 vect2.cpp

cpp 复制代码
// vect2.cpp -- methods and iterators
#include <iostream>
#include <string>
#include <vector>

struct Review {
    std::string title;
    int rating;
};
bool FillReview(Review & rr);
void ShowReview(const Review & rr);

int main()
{
    using std::cout;
    using std::vector;
    vector<Review> books;
    Review temp;
    while (FillReview(temp))
        books.push_back(temp);
    int num = books.size();
    if (num > 0)
    {
        cout << "Thank you. You entered the following:\n"
            << "Rating\tBook\n";
        for (int i = 0; i < num; i++)
            ShowReview(books[i]);
        cout << "Reprising:\n"
            << "Rating\tBook\n";
        vector<Review>::iterator pr;
        for (pr = books.begin(); pr != books.end(); pr++)
            ShowReview(*pr);
        vector <Review> oldlist(books);     // copy constructor used
        if (num > 3)
        {
            // remove 2 items
            books.erase(books.begin() + 1, books.begin() + 3);
            cout << "After erasure:\n";
            for (pr = books.begin(); pr != books.end(); pr++)
                ShowReview(*pr);
            // insert 1 item
            books.insert(books.begin(), oldlist.begin() + 1,
                        oldlist.begin() + 2);
            cout << "After insertion:\n";
            for (pr = books.begin(); pr != books.end(); pr++)
                ShowReview(*pr);
        }
        books.swap(oldlist);
        cout << "Swapping oldlist with books:\n";
        for (pr = books.begin(); pr != books.end(); pr++)
            ShowReview(*pr);
    }
    else
        cout << "Nothing entered, nothing gained.\n";
    // std::cin.get();
	return 0;
}

bool FillReview(Review & rr)
{
    std::cout << "Enter book title (quit to quit): ";
    std::getline(std::cin,rr.title);
    if (rr.title == "quit")
        return false;
    std::cout << "Enter book rating: ";
    std::cin >> rr.rating;
    if (!std::cin)
        return false;
    // get rid of rest of input line
    while (std::cin.get() != '\n')
        continue;
    return true;
}

void ShowReview(const Review & rr)
{
    std::cout << rr.rating << "\t" << rr.title << std::endl; 
}
相关推荐
新手小袁_J2 分钟前
JDK11下载安装和配置超详细过程
java·spring cloud·jdk·maven·mybatis·jdk11
呆呆小雅3 分钟前
C#关键字volatile
java·redis·c#
Monly213 分钟前
Java(若依):修改Tomcat的版本
java·开发语言·tomcat
boligongzhu4 分钟前
DALSA工业相机SDK二次开发(图像采集及保存)C#版
开发语言·c#·dalsa
Eric.Lee20215 分钟前
moviepy将图片序列制作成视频并加载字幕 - python 实现
开发语言·python·音视频·moviepy·字幕视频合成·图像制作为视频
小俊俊的博客5 分钟前
海康RGBD相机使用C++和Opencv采集图像记录
c++·opencv·海康·rgbd相机
Ttang236 分钟前
Tomcat原理(6)——tomcat完整实现
java·tomcat
7yewh7 分钟前
嵌入式Linux QT+OpenCV基于人脸识别的考勤系统 项目
linux·开发语言·arm开发·驱动开发·qt·opencv·嵌入式linux
钱多多_qdd17 分钟前
spring cache源码解析(四)——从@EnableCaching开始来阅读源码
java·spring boot·spring
waicsdn_haha19 分钟前
Java/JDK下载、安装及环境配置超详细教程【Windows10、macOS和Linux图文详解】
java·运维·服务器·开发语言·windows·后端·jdk