C++ Primer书上这个例子讲的很不错,写写帮助自己理解标准库和智能指针。
.h 文件内容
#include <fstream>
#include <iostream>
#include <vector>
#include <string>
#include <map>
#include <set>
#include <sstream>
#include <memory> class QueryResult; class TextQuery { public: using line_no = std::vector<std::string>::size_type; TextQuery(std::ifstream& ifs); // 返回string的信息
QueryResult query(const std::string&) const; private: std::shared_ptr<std::vector<std::string>> words_file;
std::map<std::string, std::shared_ptr<std::set<line_no>>> wm; }; class QueryResult { friend std::ostream& print(std::ostream&, const QueryResult&);
public: QueryResult(std::string s, std::shared_ptr<std::vector<std::string>> wf, std::shared_ptr<std::set<size_t>> l) : sought(s), file(wf), lines(l){} private:
std::string sought; // 要查询的单词
std::shared_ptr<std::vector<std::string>> file; // 输入文件
std::shared_ptr<std::set<size_t>> lines; // 保存出现的行号 };
.cpp 文件内容
#include "TextQuery.h" TextQuery::TextQuery(std::ifstream& ifs) : words_file(new std::vector<std::string>)
{
std::string text;
while (getline(ifs, text)){ words_file->push_back(text);
// 记录当前行号
size_t n = words_file->size() - 1; // 获取每行每个单词
std::istringstream line(text);
std::string word;
while (line >> word){ auto &ckeck = wm[word];
if (nullptr == ckeck)
ckeck.reset(new std::set<line_no>); ckeck->insert(n); }
} } QueryResult TextQuery::query(const std::string& s) const { // 保存一个静态对象 如果未能找到单词,返回此对象
static std::shared_ptr<std::set<size_t>> nodata(new std::set<size_t>); auto location = wm.find(s); if (location == wm.end())
return QueryResult(s, words_file, nodata);
else
return QueryResult(s, words_file, location->second);
} std::ostream& print(std::ostream& os, const QueryResult& qr){ os << qr.sought << " occurs " << qr.lines->size() << " "
<< (qr.lines->size() > 1 ? "times" : "time") << std::endl; for (auto num : *qr.lines)
os << "\t(line " << num + 1 << ")"
<< *(qr.file->begin() + num) << std::endl;
return os;
}
将TextQuery的word_file成员和wm的值set都放在智能指针内,以便QueryResult类可以在正常访问。
TextQuery类:
TextqUuery的构造函数接受一个ifstream,用来读取文件,构造函数的初始化列表中,并且将word_file初始化为一个空的vector, getline从文件中读取一行存入string text中,首先将这一行的内容储存在word_file中,然后计算该行的行号,即就是word_file的大小size() - 1,istringstream对象用来读取string text中的每个单词,如果单词不在wm中,将这个单词对应的set申请一个新的内存空间, 然后将这个单词存入wm的string中,并将它所在的行号存入wm的set中,如果这个单词存在wm中,即使这个单词是第二次或第二次之后出现在同一行,lines->insert(n)并不会执行,因为set不允许重复关键字出现。
QueryResult类中,print函数将查找到的结果输出到屏幕。
QueryResult的构造函数接受一个string,一个shared_ptr,类型为set<size_t>, 还有一个shared_ptr,类型为vector<string>,参数string表示要查询的单词,sett的shared_ptr指向TextQuery的wm中的set,vector的shared_ptr指向TextQuery中的word_file。
TextQuerty中的query函数接受一个string,表示要查询的单词,在函数里声明了一个静态智能指针类型,用来表示未找到单词的set,表示没有该单词的行数可显示,然后在wm中查找该单词。
print函数用于打印给定的QueryResult对象:如果找到了单词,先打印这个单词和出现的次数,qr.lines->size();表示这个set的大小,即就是表示这个单词出现的次数;
然后在for循环中,num依次获取到这个单词出现的行数,由于我们习惯从1开始计数,因此将num + 1;然后在file中找到这一行的数据,*(qr.file->begin() + num), 从file这个vector的首元素开始向后便宜num个元素,即就是我们这个单词出现的那一行,然后我们解引用获得这给一行的string,并将它打印出来。