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; 
}
相关推荐
ChinaRainbowSea2 分钟前
9. RabbitMQ 消息队列幂等性,优先级队列,惰性队列的详细说明
java·javascript·分布式·后端·rabbitmq·ruby·java-rabbitmq
cccccchd8 分钟前
IDEA 中右侧没有显示Maven
java
我是唐青枫13 分钟前
C# virtual 和 abstract 详解
开发语言·c#·.net
TDengine (老段)21 分钟前
TDengine.C/C++ 连接器
大数据·c语言·数据库·c++·时序数据库·tdengine·iotdb
写bug写bug28 分钟前
图解六种常见负载均衡算法,一看就懂!
java·后端·负载均衡
追光的独行者31 分钟前
Springboot框架—单元测试操作
java·spring boot·单元测试
qq_5895681034 分钟前
java学习笔记13——IO流
java·笔记·学习·intellij-idea
隔壁小查35 分钟前
【后端开发】Maven
java·maven
快乐的木子李41 分钟前
Java spring mybatis面试题(200道),八股文
java·开发语言·spring·mybatis
q5673152342 分钟前
使用Pholcus编写Go爬虫示例
开发语言·爬虫·golang